Annotation of embedaddon/php/main/SAPI.c, revision 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>