Annotation of embedaddon/php/main/SAPI.c, revision 1.1.1.1
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
5: | Copyright (c) 1997-2012 The PHP Group |
6: +----------------------------------------------------------------------+
7: | This source file is subject to version 3.01 of the PHP license, |
8: | that is bundled with this package in the file LICENSE, and is |
9: | available through the world-wide-web at the following url: |
10: | http://www.php.net/license/3_01.txt |
11: | If you did not receive a copy of the PHP license and are unable to |
12: | obtain it through the world-wide-web, please send a note to |
13: | license@php.net so we can mail you a copy immediately. |
14: +----------------------------------------------------------------------+
15: | Original design: Shane Caraveo <shane@caraveo.com> |
16: | Authors: Andi Gutmans <andi@zend.com> |
17: | Zeev Suraski <zeev@zend.com> |
18: +----------------------------------------------------------------------+
19: */
20:
21: /* $Id: SAPI.c 321634 2012-01-01 13:15:04Z felipe $ */
22:
23: #include <ctype.h>
24: #include <sys/stat.h>
25:
26: #include "php.h"
27: #include "SAPI.h"
28: #include "php_variables.h"
29: #include "php_ini.h"
30: #include "ext/standard/php_string.h"
31: #include "ext/standard/pageinfo.h"
32: #if (HAVE_PCRE || HAVE_BUNDLED_PCRE) && !defined(COMPILE_DL_PCRE)
33: #include "ext/pcre/php_pcre.h"
34: #endif
35: #ifdef ZTS
36: #include "TSRM.h"
37: #endif
38: #ifdef HAVE_SYS_TIME_H
39: #include <sys/time.h>
40: #endif
41:
42: #include "rfc1867.h"
43:
44: #ifdef PHP_WIN32
45: #define STRCASECMP stricmp
46: #else
47: #define STRCASECMP strcasecmp
48: #endif
49:
50: #include "php_content_types.h"
51:
52: #ifdef ZTS
53: SAPI_API int sapi_globals_id;
54: #else
55: sapi_globals_struct sapi_globals;
56: #endif
57:
58: static void sapi_globals_ctor(sapi_globals_struct *sapi_globals TSRMLS_DC)
59: {
60: memset(sapi_globals, 0, sizeof(*sapi_globals));
61: zend_hash_init_ex(&sapi_globals->known_post_content_types, 5, NULL, NULL, 1, 0);
62: php_setup_sapi_content_types(TSRMLS_C);
63: }
64:
65: static void sapi_globals_dtor(sapi_globals_struct *sapi_globals TSRMLS_DC)
66: {
67: zend_hash_destroy(&sapi_globals->known_post_content_types);
68: }
69:
70: /* True globals (no need for thread safety) */
71: SAPI_API sapi_module_struct sapi_module;
72:
73:
74: SAPI_API void sapi_startup(sapi_module_struct *sf)
75: {
76: sf->ini_entries = NULL;
77: sapi_module = *sf;
78:
79: #ifdef ZTS
80: ts_allocate_id(&sapi_globals_id, sizeof(sapi_globals_struct), (ts_allocate_ctor) sapi_globals_ctor, (ts_allocate_dtor) sapi_globals_dtor);
81: # ifdef PHP_WIN32
82: _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
83: # endif
84: #else
85: sapi_globals_ctor(&sapi_globals);
86: #endif
87:
88: virtual_cwd_startup(); /* Could use shutdown to free the main cwd but it would just slow it down for CGI */
89:
90: #ifdef PHP_WIN32
91: tsrm_win32_startup();
92: #endif
93:
94: reentrancy_startup();
95: }
96:
97: SAPI_API void sapi_shutdown(void)
98: {
99: #ifdef ZTS
100: ts_free_id(sapi_globals_id);
101: #else
102: sapi_globals_dtor(&sapi_globals);
103: #endif
104:
105: reentrancy_shutdown();
106:
107: virtual_cwd_shutdown();
108:
109: #ifdef PHP_WIN32
110: tsrm_win32_shutdown();
111: #endif
112: }
113:
114:
115: SAPI_API void sapi_free_header(sapi_header_struct *sapi_header)
116: {
117: efree(sapi_header->header);
118: }
119:
120:
121: SAPI_API void sapi_handle_post(void *arg TSRMLS_DC)
122: {
123: if (SG(request_info).post_entry && SG(request_info).content_type_dup) {
124: SG(request_info).post_entry->post_handler(SG(request_info).content_type_dup, arg TSRMLS_CC);
125: if (SG(request_info).post_data) {
126: efree(SG(request_info).post_data);
127: SG(request_info).post_data = NULL;
128: }
129: efree(SG(request_info).content_type_dup);
130: SG(request_info).content_type_dup = NULL;
131: }
132: }
133:
134: static void sapi_read_post_data(TSRMLS_D)
135: {
136: sapi_post_entry *post_entry;
137: uint content_type_length = strlen(SG(request_info).content_type);
138: char *content_type = estrndup(SG(request_info).content_type, content_type_length);
139: char *p;
140: char oldchar=0;
141: void (*post_reader_func)(TSRMLS_D) = NULL;
142:
143:
144: /* dedicated implementation for increased performance:
145: * - Make the content type lowercase
146: * - Trim descriptive data, stay with the content-type only
147: */
148: for (p=content_type; p<content_type+content_type_length; p++) {
149: switch (*p) {
150: case ';':
151: case ',':
152: case ' ':
153: content_type_length = p-content_type;
154: oldchar = *p;
155: *p = 0;
156: break;
157: default:
158: *p = tolower(*p);
159: break;
160: }
161: }
162:
163: /* now try to find an appropriate POST content handler */
164: if (zend_hash_find(&SG(known_post_content_types), content_type,
165: content_type_length+1, (void **) &post_entry) == SUCCESS) {
166: /* found one, register it for use */
167: SG(request_info).post_entry = post_entry;
168: post_reader_func = post_entry->post_reader;
169: } else {
170: /* fallback */
171: SG(request_info).post_entry = NULL;
172: if (!sapi_module.default_post_reader) {
173: /* no default reader ? */
174: SG(request_info).content_type_dup = NULL;
175: sapi_module.sapi_error(E_WARNING, "Unsupported content type: '%s'", content_type);
176: return;
177: }
178: }
179: if (oldchar) {
180: *(p-1) = oldchar;
181: }
182:
183: SG(request_info).content_type_dup = content_type;
184:
185: if(post_reader_func) {
186: post_reader_func(TSRMLS_C);
187: }
188:
189: if(sapi_module.default_post_reader) {
190: sapi_module.default_post_reader(TSRMLS_C);
191: }
192: }
193:
194:
195: SAPI_API SAPI_POST_READER_FUNC(sapi_read_standard_form_data)
196: {
197: int read_bytes;
198: int allocated_bytes=SAPI_POST_BLOCK_SIZE+1;
199:
200: if ((SG(post_max_size) > 0) && (SG(request_info).content_length > SG(post_max_size))) {
201: php_error_docref(NULL TSRMLS_CC, E_WARNING, "POST Content-Length of %ld bytes exceeds the limit of %ld bytes",
202: SG(request_info).content_length, SG(post_max_size));
203: return;
204: }
205: SG(request_info).post_data = emalloc(allocated_bytes);
206:
207: for (;;) {
208: read_bytes = sapi_module.read_post(SG(request_info).post_data+SG(read_post_bytes), SAPI_POST_BLOCK_SIZE TSRMLS_CC);
209: if (read_bytes<=0) {
210: break;
211: }
212: SG(read_post_bytes) += read_bytes;
213: if ((SG(post_max_size) > 0) && (SG(read_post_bytes) > SG(post_max_size))) {
214: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Actual POST length does not match Content-Length, and exceeds %ld bytes", SG(post_max_size));
215: break;
216: }
217: if (read_bytes < SAPI_POST_BLOCK_SIZE) {
218: break;
219: }
220: if (SG(read_post_bytes)+SAPI_POST_BLOCK_SIZE >= allocated_bytes) {
221: allocated_bytes = SG(read_post_bytes)+SAPI_POST_BLOCK_SIZE+1;
222: SG(request_info).post_data = erealloc(SG(request_info).post_data, allocated_bytes);
223: }
224: }
225: SG(request_info).post_data[SG(read_post_bytes)] = 0; /* terminating NULL */
226: SG(request_info).post_data_length = SG(read_post_bytes);
227: }
228:
229:
230: SAPI_API char *sapi_get_default_content_type(TSRMLS_D)
231: {
232: char *mimetype, *charset, *content_type;
233:
234: mimetype = SG(default_mimetype) ? SG(default_mimetype) : SAPI_DEFAULT_MIMETYPE;
235: charset = SG(default_charset) ? SG(default_charset) : SAPI_DEFAULT_CHARSET;
236:
237: if (strncasecmp(mimetype, "text/", 5) == 0 && *charset) {
238: int len = strlen(mimetype) + sizeof("; charset=") + strlen(charset); /* sizeof() includes \0 */
239: content_type = emalloc(len);
240: snprintf(content_type, len, "%s; charset=%s", mimetype, charset);
241: } else {
242: content_type = estrdup(mimetype);
243: }
244: return content_type;
245: }
246:
247:
248: SAPI_API void sapi_get_default_content_type_header(sapi_header_struct *default_header TSRMLS_DC)
249: {
250: char *default_content_type = sapi_get_default_content_type(TSRMLS_C);
251: int default_content_type_len = strlen(default_content_type);
252:
253: default_header->header_len = (sizeof("Content-type: ")-1) + default_content_type_len;
254: default_header->header = emalloc(default_header->header_len+1);
255: memcpy(default_header->header, "Content-type: ", sizeof("Content-type: "));
256: memcpy(default_header->header+sizeof("Content-type: ")-1, default_content_type, default_content_type_len);
257: default_header->header[default_header->header_len] = 0;
258: efree(default_content_type);
259: }
260:
261: /*
262: * Add charset on content-type header if the MIME type starts with
263: * "text/", the default_charset directive is not empty and
264: * there is not already a charset option in there.
265: *
266: * If "mimetype" is non-NULL, it should point to a pointer allocated
267: * with emalloc(). If a charset is added, the string will be
268: * re-allocated and the new length is returned. If mimetype is
269: * unchanged, 0 is returned.
270: *
271: */
272: SAPI_API size_t sapi_apply_default_charset(char **mimetype, size_t len TSRMLS_DC)
273: {
274: char *charset, *newtype;
275: size_t newlen;
276: charset = SG(default_charset) ? SG(default_charset) : SAPI_DEFAULT_CHARSET;
277:
278: if (*mimetype != NULL) {
279: if (*charset && strncmp(*mimetype, "text/", 5) == 0 && strstr(*mimetype, "charset=") == NULL) {
280: newlen = len + (sizeof(";charset=")-1) + strlen(charset);
281: newtype = emalloc(newlen + 1);
282: PHP_STRLCPY(newtype, *mimetype, newlen + 1, len);
283: strlcat(newtype, ";charset=", newlen + 1);
284: strlcat(newtype, charset, newlen + 1);
285: efree(*mimetype);
286: *mimetype = newtype;
287: return newlen;
288: }
289: }
290: return 0;
291: }
292:
293: SAPI_API void sapi_activate_headers_only(TSRMLS_D)
294: {
295: if (SG(request_info).headers_read == 1)
296: return;
297: SG(request_info).headers_read = 1;
298: zend_llist_init(&SG(sapi_headers).headers, sizeof(sapi_header_struct),
299: (void (*)(void *)) sapi_free_header, 0);
300: SG(sapi_headers).send_default_content_type = 1;
301:
302: /* SG(sapi_headers).http_response_code = 200; */
303: SG(sapi_headers).http_status_line = NULL;
304: SG(sapi_headers).mimetype = NULL;
305: SG(read_post_bytes) = 0;
306: SG(request_info).post_data = NULL;
307: SG(request_info).raw_post_data = NULL;
308: SG(request_info).current_user = NULL;
309: SG(request_info).current_user_length = 0;
310: SG(request_info).no_headers = 0;
311: SG(request_info).post_entry = NULL;
312: SG(global_request_time) = 0;
313:
314: /*
315: * It's possible to override this general case in the activate() callback,
316: * if necessary.
317: */
318: if (SG(request_info).request_method && !strcmp(SG(request_info).request_method, "HEAD")) {
319: SG(request_info).headers_only = 1;
320: } else {
321: SG(request_info).headers_only = 0;
322: }
323: if (SG(server_context)) {
324: SG(request_info).cookie_data = sapi_module.read_cookies(TSRMLS_C);
325: if (sapi_module.activate) {
326: sapi_module.activate(TSRMLS_C);
327: }
328: }
329: if (sapi_module.input_filter_init ) {
330: sapi_module.input_filter_init(TSRMLS_C);
331: }
332: }
333:
334: /*
335: * Called from php_request_startup() for every request.
336: */
337:
338: SAPI_API void sapi_activate(TSRMLS_D)
339: {
340: zend_llist_init(&SG(sapi_headers).headers, sizeof(sapi_header_struct), (void (*)(void *)) sapi_free_header, 0);
341: SG(sapi_headers).send_default_content_type = 1;
342:
343: /*
344: SG(sapi_headers).http_response_code = 200;
345: */
346: SG(sapi_headers).http_status_line = NULL;
347: SG(sapi_headers).mimetype = NULL;
348: SG(headers_sent) = 0;
349: SG(read_post_bytes) = 0;
350: SG(request_info).post_data = NULL;
351: SG(request_info).raw_post_data = NULL;
352: SG(request_info).current_user = NULL;
353: SG(request_info).current_user_length = 0;
354: SG(request_info).no_headers = 0;
355: SG(request_info).post_entry = NULL;
356: SG(request_info).proto_num = 1000; /* Default to HTTP 1.0 */
357: SG(global_request_time) = 0;
358:
359: /* It's possible to override this general case in the activate() callback, if
360: * necessary.
361: */
362: if (SG(request_info).request_method && !strcmp(SG(request_info).request_method, "HEAD")) {
363: SG(request_info).headers_only = 1;
364: } else {
365: SG(request_info).headers_only = 0;
366: }
367: SG(rfc1867_uploaded_files) = NULL;
368:
369: /* handle request mehtod */
370: if (SG(server_context)) {
371: if ( SG(request_info).request_method) {
372: if(!strcmp(SG(request_info).request_method, "POST")
373: && (SG(request_info).content_type)) {
374: /* HTTP POST -> may contain form data to be read into variables
375: depending on content type given
376: */
377: sapi_read_post_data(TSRMLS_C);
378: } else {
379: /* any other method with content payload will fill
380: $HTTP_RAW_POST_DATA if enabled by always_populate_raw_post_data
381: it is up to the webserver to decide whether to allow a method or not
382: */
383: SG(request_info).content_type_dup = NULL;
384: if(sapi_module.default_post_reader) {
385: sapi_module.default_post_reader(TSRMLS_C);
386: }
387: }
388: } else {
389: SG(request_info).content_type_dup = NULL;
390: }
391:
392: /* Cookies */
393: SG(request_info).cookie_data = sapi_module.read_cookies(TSRMLS_C);
394: if (sapi_module.activate) {
395: sapi_module.activate(TSRMLS_C);
396: }
397: }
398: if (sapi_module.input_filter_init ) {
399: sapi_module.input_filter_init(TSRMLS_C);
400: }
401: }
402:
403:
404: static void sapi_send_headers_free(TSRMLS_D)
405: {
406: if (SG(sapi_headers).http_status_line) {
407: efree(SG(sapi_headers).http_status_line);
408: SG(sapi_headers).http_status_line = NULL;
409: }
410: }
411:
412: SAPI_API void sapi_deactivate(TSRMLS_D)
413: {
414: zend_llist_destroy(&SG(sapi_headers).headers);
415: if (SG(request_info).post_data) {
416: efree(SG(request_info).post_data);
417: } else if (SG(server_context)) {
418: if(sapi_module.read_post) {
419: /* make sure we've consumed all request input data */
420: char dummy[SAPI_POST_BLOCK_SIZE];
421: int read_bytes;
422:
423: while((read_bytes = sapi_module.read_post(dummy, sizeof(dummy)-1 TSRMLS_CC)) > 0) {
424: SG(read_post_bytes) += read_bytes;
425: }
426: }
427: }
428: if (SG(request_info).raw_post_data) {
429: efree(SG(request_info).raw_post_data);
430: }
431: if (SG(request_info).auth_user) {
432: efree(SG(request_info).auth_user);
433: }
434: if (SG(request_info).auth_password) {
435: efree(SG(request_info).auth_password);
436: }
437: if (SG(request_info).auth_digest) {
438: efree(SG(request_info).auth_digest);
439: }
440: if (SG(request_info).content_type_dup) {
441: efree(SG(request_info).content_type_dup);
442: }
443: if (SG(request_info).current_user) {
444: efree(SG(request_info).current_user);
445: }
446: if (sapi_module.deactivate) {
447: sapi_module.deactivate(TSRMLS_C);
448: }
449: if (SG(rfc1867_uploaded_files)) {
450: destroy_uploaded_files_hash(TSRMLS_C);
451: }
452: if (SG(sapi_headers).mimetype) {
453: efree(SG(sapi_headers).mimetype);
454: SG(sapi_headers).mimetype = NULL;
455: }
456: sapi_send_headers_free(TSRMLS_C);
457: SG(sapi_started) = 0;
458: SG(headers_sent) = 0;
459: SG(request_info).headers_read = 0;
460: SG(global_request_time) = 0;
461: }
462:
463:
464: SAPI_API void sapi_initialize_empty_request(TSRMLS_D)
465: {
466: SG(server_context) = NULL;
467: SG(request_info).request_method = NULL;
468: SG(request_info).auth_digest = SG(request_info).auth_user = SG(request_info).auth_password = NULL;
469: SG(request_info).content_type_dup = NULL;
470: }
471:
472:
473: static int sapi_extract_response_code(const char *header_line)
474: {
475: int code = 200;
476: const char *ptr;
477:
478: for (ptr = header_line; *ptr; ptr++) {
479: if (*ptr == ' ' && *(ptr + 1) != ' ') {
480: code = atoi(ptr + 1);
481: break;
482: }
483: }
484:
485: return code;
486: }
487:
488:
489: static void sapi_update_response_code(int ncode TSRMLS_DC)
490: {
491: /* if the status code did not change, we do not want
492: to change the status line, and no need to change the code */
493: if (SG(sapi_headers).http_response_code == ncode) {
494: return;
495: }
496:
497: if (SG(sapi_headers).http_status_line) {
498: efree(SG(sapi_headers).http_status_line);
499: SG(sapi_headers).http_status_line = NULL;
500: }
501: SG(sapi_headers).http_response_code = ncode;
502: }
503:
504: static int sapi_find_matching_header(void *element1, void *element2)
505: {
506: int len = strlen((char*)element2);
507: return strncasecmp(((sapi_header_struct*)element1)->header, (char*)element2, len) == 0 && ((sapi_header_struct*)element1)->header[len] == ':';
508: }
509:
510: SAPI_API int sapi_add_header_ex(char *header_line, uint header_line_len, zend_bool duplicate, zend_bool replace TSRMLS_DC)
511: {
512: sapi_header_line ctr = {0};
513: int r;
514:
515: ctr.line = header_line;
516: ctr.line_len = header_line_len;
517:
518: r = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD,
519: &ctr TSRMLS_CC);
520:
521: if (!duplicate)
522: efree(header_line);
523:
524: return r;
525: }
526:
527: SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC)
528: {
529: int retval;
530: sapi_header_struct sapi_header;
531: char *colon_offset;
532: long myuid = 0L;
533: char *header_line;
534: uint header_line_len;
535: int http_response_code;
536:
537: if (SG(headers_sent) && !SG(request_info).no_headers) {
538: char *output_start_filename = php_get_output_start_filename(TSRMLS_C);
539: int output_start_lineno = php_get_output_start_lineno(TSRMLS_C);
540:
541: if (output_start_filename) {
542: sapi_module.sapi_error(E_WARNING, "Cannot modify header information - headers already sent by (output started at %s:%d)",
543: output_start_filename, output_start_lineno);
544: } else {
545: sapi_module.sapi_error(E_WARNING, "Cannot modify header information - headers already sent");
546: }
547: return FAILURE;
548: }
549:
550: switch (op) {
551: case SAPI_HEADER_SET_STATUS:
552: sapi_update_response_code((int)(zend_intptr_t) arg TSRMLS_CC);
553: return SUCCESS;
554:
555: case SAPI_HEADER_ADD:
556: case SAPI_HEADER_REPLACE:
557: case SAPI_HEADER_DELETE: {
558: sapi_header_line *p = arg;
559:
560: if (!p->line || !p->line_len) {
561: return FAILURE;
562: }
563: header_line = p->line;
564: header_line_len = p->line_len;
565: http_response_code = p->response_code;
566: break;
567: }
568:
569: case SAPI_HEADER_DELETE_ALL:
570: if (sapi_module.header_handler) {
571: sapi_module.header_handler(&sapi_header, op, &SG(sapi_headers) TSRMLS_CC);
572: }
573: zend_llist_clean(&SG(sapi_headers).headers);
574: return SUCCESS;
575:
576: default:
577: return FAILURE;
578: }
579:
580: header_line = estrndup(header_line, header_line_len);
581:
582: /* cut of trailing spaces, linefeeds and carriage-returns */
583: while(header_line_len && isspace(header_line[header_line_len-1]))
584: header_line[--header_line_len]='\0';
585:
586: if (op == SAPI_HEADER_DELETE) {
587: if (strchr(header_line, ':')) {
588: efree(header_line);
589: sapi_module.sapi_error(E_WARNING, "Header to delete may not contain colon.");
590: return FAILURE;
591: }
592: } else {
593: /* new line safety check */
594: char *s = header_line, *e = header_line + header_line_len, *p;
595: while (s < e && (p = memchr(s, '\n', (e - s)))) {
596: if (*(p + 1) == ' ' || *(p + 1) == '\t') {
597: s = p + 1;
598: continue;
599: }
600: efree(header_line);
601: sapi_module.sapi_error(E_WARNING, "Header may not contain more than a single header, new line detected.");
602: return FAILURE;
603: }
604: }
605:
606: sapi_header.header = header_line;
607: sapi_header.header_len = header_line_len;
608:
609: if (op == SAPI_HEADER_DELETE) {
610: if (sapi_module.header_handler) {
611: sapi_module.header_handler(&sapi_header, op, &SG(sapi_headers) TSRMLS_CC);
612: }
613: zend_llist_del_element(&SG(sapi_headers).headers, sapi_header.header, (int(*)(void*, void*))sapi_find_matching_header);
614: sapi_free_header(&sapi_header);
615: return SUCCESS;
616: }
617:
618: /* Check the header for a few cases that we have special support for in SAPI */
619: if (header_line_len>=5
620: && !strncasecmp(header_line, "HTTP/", 5)) {
621: /* filter out the response code */
622: sapi_update_response_code(sapi_extract_response_code(header_line) TSRMLS_CC);
623: /* sapi_update_response_code doesn't free the status line if the code didn't change */
624: if (SG(sapi_headers).http_status_line) {
625: efree(SG(sapi_headers).http_status_line);
626: }
627: SG(sapi_headers).http_status_line = header_line;
628: return SUCCESS;
629: } else {
630: colon_offset = strchr(header_line, ':');
631: if (colon_offset) {
632: *colon_offset = 0;
633: if (!STRCASECMP(header_line, "Content-Type")) {
634: char *ptr = colon_offset+1, *mimetype = NULL, *newheader;
635: size_t len = header_line_len - (ptr - header_line), newlen;
636: while (*ptr == ' ') {
637: ptr++;
638: len--;
639: }
640:
641: /* Disable possible output compression for images */
642: if (!strncmp(ptr, "image/", sizeof("image/")-1)) {
643: zend_alter_ini_entry("zlib.output_compression", sizeof("zlib.output_compression"), "0", sizeof("0") - 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
644: }
645:
646: mimetype = estrdup(ptr);
647: newlen = sapi_apply_default_charset(&mimetype, len TSRMLS_CC);
648: if (!SG(sapi_headers).mimetype){
649: SG(sapi_headers).mimetype = estrdup(mimetype);
650: }
651:
652: if (newlen != 0) {
653: newlen += sizeof("Content-type: ");
654: newheader = emalloc(newlen);
655: PHP_STRLCPY(newheader, "Content-type: ", newlen, sizeof("Content-type: ")-1);
656: strlcat(newheader, mimetype, newlen);
657: sapi_header.header = newheader;
658: sapi_header.header_len = newlen - 1;
659: efree(header_line);
660: }
661: efree(mimetype);
662: SG(sapi_headers).send_default_content_type = 0;
663: } else if (!STRCASECMP(header_line, "Location")) {
664: if ((SG(sapi_headers).http_response_code < 300 ||
665: SG(sapi_headers).http_response_code > 307) &&
666: SG(sapi_headers).http_response_code != 201) {
667: /* Return a Found Redirect if one is not already specified */
668: if (http_response_code) { /* user specified redirect code */
669: sapi_update_response_code(http_response_code TSRMLS_CC);
670: } else if (SG(request_info).proto_num > 1000 &&
671: SG(request_info).request_method &&
672: strcmp(SG(request_info).request_method, "HEAD") &&
673: strcmp(SG(request_info).request_method, "GET")) {
674: sapi_update_response_code(303 TSRMLS_CC);
675: } else {
676: sapi_update_response_code(302 TSRMLS_CC);
677: }
678: }
679: } else if (!STRCASECMP(header_line, "WWW-Authenticate")) { /* HTTP Authentication */
680:
681: sapi_update_response_code(401 TSRMLS_CC); /* authentication-required */
682:
683: if(PG(safe_mode))
684: #if (HAVE_PCRE || HAVE_BUNDLED_PCRE) && !defined(COMPILE_DL_PCRE)
685: {
686: zval *repl_temp;
687: char *ptr = colon_offset+1, *result, *newheader;
688: int ptr_len=0, result_len = 0, newlen = 0;
689:
690: /* skip white space */
691: while (isspace(*ptr)) {
692: ptr++;
693: }
694:
695: myuid = php_getuid();
696:
697: ptr_len = strlen(ptr);
698: MAKE_STD_ZVAL(repl_temp);
699: Z_TYPE_P(repl_temp) = IS_STRING;
700: Z_STRLEN_P(repl_temp) = spprintf(&Z_STRVAL_P(repl_temp), 0, "realm=\"\\1-%ld\"", myuid);
701: /* Modify quoted realm value */
702: result = php_pcre_replace("/realm=\"(.*?)\"/i", 16,
703: ptr, ptr_len,
704: repl_temp,
705: 0, &result_len, -1, NULL TSRMLS_CC);
706: if(result_len==ptr_len) {
707: efree(result);
708: efree(Z_STRVAL_P(repl_temp));
709: Z_STRLEN_P(repl_temp) = spprintf(&Z_STRVAL_P(repl_temp), 0, "realm=\\1-%ld\\2", myuid);
710: /* modify unquoted realm value */
711: result = php_pcre_replace("/realm=([^\\s]+)(.*)/i", 21,
712: ptr, ptr_len,
713: repl_temp,
714: 0, &result_len, -1, NULL TSRMLS_CC);
715: if(result_len==ptr_len) {
716: char *lower_temp = estrdup(ptr);
717: char conv_temp[32];
718: int conv_len;
719:
720: php_strtolower(lower_temp,strlen(lower_temp));
721: /* If there is no realm string at all, append one */
722: if(!strstr(lower_temp,"realm")) {
723: efree(result);
724: conv_len = slprintf(conv_temp, sizeof(conv_temp), " realm=\"%ld\"",myuid);
725: result = emalloc(ptr_len+conv_len+1);
726: result_len = ptr_len+conv_len;
727: memcpy(result, ptr, ptr_len);
728: memcpy(result+ptr_len, conv_temp, conv_len);
729: *(result+ptr_len+conv_len) = '\0';
730: }
731: efree(lower_temp);
732: }
733: }
734: newlen = spprintf(&newheader, 0, "WWW-Authenticate: %s", result);
735: efree(header_line);
736: sapi_header.header = newheader;
737: sapi_header.header_len = newlen;
738: efree(result);
739: efree(Z_STRVAL_P(repl_temp));
740: efree(repl_temp);
741: }
742: #else
743: {
744: myuid = php_getuid();
745: efree(header_line);
746: sapi_header.header_len = spprintf(&sapi_header.header, 0, "WWW-Authenticate: Basic realm=\"%ld\"", myuid);
747: }
748: #endif
749: }
750: if (sapi_header.header==header_line) {
751: *colon_offset = ':';
752: }
753: }
754: }
755: if (http_response_code) {
756: sapi_update_response_code(http_response_code TSRMLS_CC);
757: }
758: if (sapi_module.header_handler) {
759: retval = sapi_module.header_handler(&sapi_header, op, &SG(sapi_headers) TSRMLS_CC);
760: } else {
761: retval = SAPI_HEADER_ADD;
762: }
763: if (retval & SAPI_HEADER_ADD) {
764: /* in replace mode first remove the header if it already exists in the headers llist */
765: if (op == SAPI_HEADER_REPLACE) {
766: colon_offset = strchr(sapi_header.header, ':');
767: if (colon_offset) {
768: char sav;
769: sav = *colon_offset;
770: *colon_offset = 0;
771: zend_llist_del_element(&SG(sapi_headers).headers, sapi_header.header, (int(*)(void*, void*))sapi_find_matching_header);
772: *colon_offset = sav;
773: }
774: }
775:
776: zend_llist_add_element(&SG(sapi_headers).headers, (void *) &sapi_header);
777: } else {
778: sapi_free_header(&sapi_header);
779: }
780: return SUCCESS;
781: }
782:
783:
784: SAPI_API int sapi_send_headers(TSRMLS_D)
785: {
786: int retval;
787: int ret = FAILURE;
788:
789: if (SG(headers_sent) || SG(request_info).no_headers) {
790: return SUCCESS;
791: }
792:
793: /* Success-oriented. We set headers_sent to 1 here to avoid an infinite loop
794: * in case of an error situation.
795: */
796: if (SG(sapi_headers).send_default_content_type && sapi_module.send_headers) {
797: sapi_header_struct default_header;
798: sapi_get_default_content_type_header(&default_header TSRMLS_CC);
799: sapi_add_header_ex(default_header.header, default_header.header_len, 0, 0 TSRMLS_CC);
800: }
801:
802: SG(headers_sent) = 1;
803:
804: if (sapi_module.send_headers) {
805: retval = sapi_module.send_headers(&SG(sapi_headers) TSRMLS_CC);
806: } else {
807: retval = SAPI_HEADER_DO_SEND;
808: }
809:
810: switch (retval) {
811: case SAPI_HEADER_SENT_SUCCESSFULLY:
812: ret = SUCCESS;
813: break;
814: case SAPI_HEADER_DO_SEND: {
815: sapi_header_struct http_status_line;
816: char buf[255];
817:
818: if (SG(sapi_headers).http_status_line) {
819: http_status_line.header = SG(sapi_headers).http_status_line;
820: http_status_line.header_len = strlen(SG(sapi_headers).http_status_line);
821: } else {
822: http_status_line.header = buf;
823: http_status_line.header_len = slprintf(buf, sizeof(buf), "HTTP/1.0 %d X", SG(sapi_headers).http_response_code);
824: }
825: sapi_module.send_header(&http_status_line, SG(server_context) TSRMLS_CC);
826: }
827: zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t) sapi_module.send_header, SG(server_context) TSRMLS_CC);
828: if(SG(sapi_headers).send_default_content_type) {
829: sapi_header_struct default_header;
830:
831: sapi_get_default_content_type_header(&default_header TSRMLS_CC);
832: sapi_module.send_header(&default_header, SG(server_context) TSRMLS_CC);
833: sapi_free_header(&default_header);
834: }
835: sapi_module.send_header(NULL, SG(server_context) TSRMLS_CC);
836: ret = SUCCESS;
837: break;
838: case SAPI_HEADER_SEND_FAILED:
839: SG(headers_sent) = 0;
840: ret = FAILURE;
841: break;
842: }
843:
844: sapi_send_headers_free(TSRMLS_C);
845:
846: return ret;
847: }
848:
849:
850: SAPI_API int sapi_register_post_entries(sapi_post_entry *post_entries TSRMLS_DC)
851: {
852: sapi_post_entry *p=post_entries;
853:
854: while (p->content_type) {
855: if (sapi_register_post_entry(p TSRMLS_CC) == FAILURE) {
856: return FAILURE;
857: }
858: p++;
859: }
860: return SUCCESS;
861: }
862:
863:
864: SAPI_API int sapi_register_post_entry(sapi_post_entry *post_entry TSRMLS_DC)
865: {
866: if (SG(sapi_started) && EG(in_execution)) {
867: return FAILURE;
868: }
869: return zend_hash_add(&SG(known_post_content_types),
870: post_entry->content_type, post_entry->content_type_len+1,
871: (void *) post_entry, sizeof(sapi_post_entry), NULL);
872: }
873:
874: SAPI_API void sapi_unregister_post_entry(sapi_post_entry *post_entry TSRMLS_DC)
875: {
876: if (SG(sapi_started) && EG(in_execution)) {
877: return;
878: }
879: zend_hash_del(&SG(known_post_content_types), post_entry->content_type,
880: post_entry->content_type_len+1);
881: }
882:
883:
884: SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(TSRMLS_D))
885: {
886: TSRMLS_FETCH();
887: if (SG(sapi_started) && EG(in_execution)) {
888: return FAILURE;
889: }
890: sapi_module.default_post_reader = default_post_reader;
891: return SUCCESS;
892: }
893:
894:
895: SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zval *destArray TSRMLS_DC))
896: {
897: TSRMLS_FETCH();
898: if (SG(sapi_started) && EG(in_execution)) {
899: return FAILURE;
900: }
901: sapi_module.treat_data = treat_data;
902: return SUCCESS;
903: }
904:
905: SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC), unsigned int (*input_filter_init)(TSRMLS_D))
906: {
907: TSRMLS_FETCH();
908: if (SG(sapi_started) && EG(in_execution)) {
909: return FAILURE;
910: }
911: sapi_module.input_filter = input_filter;
912: sapi_module.input_filter_init = input_filter_init;
913: return SUCCESS;
914: }
915:
916: SAPI_API int sapi_flush(TSRMLS_D)
917: {
918: if (sapi_module.flush) {
919: sapi_module.flush(SG(server_context));
920: return SUCCESS;
921: } else {
922: return FAILURE;
923: }
924: }
925:
926: SAPI_API struct stat *sapi_get_stat(TSRMLS_D)
927: {
928: if (sapi_module.get_stat) {
929: return sapi_module.get_stat(TSRMLS_C);
930: } else {
931: if (!SG(request_info).path_translated || (VCWD_STAT(SG(request_info).path_translated, &SG(global_stat)) == -1)) {
932: return NULL;
933: }
934: return &SG(global_stat);
935: }
936: }
937:
938: SAPI_API char *sapi_getenv(char *name, size_t name_len TSRMLS_DC)
939: {
940: if (sapi_module.getenv) {
941: char *value, *tmp = sapi_module.getenv(name, name_len TSRMLS_CC);
942: if (tmp) {
943: value = estrdup(tmp);
944: } else {
945: return NULL;
946: }
947: sapi_module.input_filter(PARSE_ENV, name, &value, strlen(value), NULL TSRMLS_CC);
948: return value;
949: }
950: return NULL;
951: }
952:
953: SAPI_API int sapi_get_fd(int *fd TSRMLS_DC)
954: {
955: if (sapi_module.get_fd) {
956: return sapi_module.get_fd(fd TSRMLS_CC);
957: } else {
958: return FAILURE;
959: }
960: }
961:
962: SAPI_API int sapi_force_http_10(TSRMLS_D)
963: {
964: if (sapi_module.force_http_10) {
965: return sapi_module.force_http_10(TSRMLS_C);
966: } else {
967: return FAILURE;
968: }
969: }
970:
971:
972: SAPI_API int sapi_get_target_uid(uid_t *obj TSRMLS_DC)
973: {
974: if (sapi_module.get_target_uid) {
975: return sapi_module.get_target_uid(obj TSRMLS_CC);
976: } else {
977: return FAILURE;
978: }
979: }
980:
981: SAPI_API int sapi_get_target_gid(gid_t *obj TSRMLS_DC)
982: {
983: if (sapi_module.get_target_gid) {
984: return sapi_module.get_target_gid(obj TSRMLS_CC);
985: } else {
986: return FAILURE;
987: }
988: }
989:
990: SAPI_API time_t sapi_get_request_time(TSRMLS_D)
991: {
992: if(SG(global_request_time)) return SG(global_request_time);
993:
994: if (sapi_module.get_request_time && SG(server_context)) {
995: SG(global_request_time) = sapi_module.get_request_time(TSRMLS_C);
996: } else {
997: SG(global_request_time) = time(0);
998: }
999: return SG(global_request_time);
1000: }
1001:
1002: SAPI_API void sapi_terminate_process(TSRMLS_D) {
1003: if (sapi_module.terminate_process) {
1004: sapi_module.terminate_process(TSRMLS_C);
1005: }
1006: }
1007:
1008: /*
1009: * Local variables:
1010: * tab-width: 4
1011: * c-basic-offset: 4
1012: * End:
1013: * vim600: sw=4 ts=4 fdm=marker
1014: * vim<600: sw=4 ts=4
1015: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>