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