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