root/main/SAPI.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sapi_globals_ctor
  2. sapi_globals_dtor
  3. sapi_startup
  4. sapi_shutdown
  5. sapi_free_header
  6. PHP_FUNCTION
  7. sapi_run_header_callback
  8. sapi_handle_post
  9. sapi_read_post_data
  10. sapi_read_post_block
  11. SAPI_POST_READER_FUNC
  12. get_default_content_type
  13. sapi_get_default_content_type
  14. sapi_get_default_content_type_header
  15. sapi_apply_default_charset
  16. sapi_activate_headers_only
  17. sapi_activate
  18. sapi_send_headers_free
  19. sapi_deactivate
  20. sapi_initialize_empty_request
  21. sapi_extract_response_code
  22. sapi_update_response_code
  23. sapi_remove_header
  24. sapi_add_header_ex
  25. sapi_header_add_op
  26. sapi_header_op
  27. sapi_send_headers
  28. sapi_register_post_entries
  29. sapi_register_post_entry
  30. sapi_unregister_post_entry
  31. sapi_register_default_post_reader
  32. sapi_register_treat_data
  33. sapi_register_input_filter
  34. sapi_flush
  35. sapi_get_stat
  36. sapi_getenv
  37. sapi_get_fd
  38. sapi_force_http_10
  39. sapi_get_target_uid
  40. sapi_get_target_gid
  41. sapi_get_request_time
  42. sapi_terminate_process

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

/* [<][>][^][v][top][bottom][index][help] */