root/main/SAPI.c

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

DEFINITIONS

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

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 7                                                        |
   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 #include "php_content_types.h"
  47 
  48 #ifdef ZTS
  49 SAPI_API int sapi_globals_id;
  50 #else
  51 sapi_globals_struct sapi_globals;
  52 #endif
  53 
  54 static void _type_dtor(zval *zv)
  55 {
  56         free(Z_PTR_P(zv));
  57 }
  58 
  59 static void sapi_globals_ctor(sapi_globals_struct *sapi_globals)
  60 {
  61 #ifdef ZTS
  62         ZEND_TSRMLS_CACHE_UPDATE();
  63 #endif
  64         memset(sapi_globals, 0, sizeof(*sapi_globals));
  65         zend_hash_init_ex(&sapi_globals->known_post_content_types, 8, NULL, _type_dtor, 1, 0);
  66         php_setup_sapi_content_types();
  67 }
  68 
  69 static void sapi_globals_dtor(sapi_globals_struct *sapi_globals)
  70 {
  71         zend_hash_destroy(&sapi_globals->known_post_content_types);
  72 }
  73 
  74 /* True globals (no need for thread safety) */
  75 SAPI_API sapi_module_struct sapi_module;
  76 
  77 
  78 SAPI_API void sapi_startup(sapi_module_struct *sf)
  79 {
  80         sf->ini_entries = NULL;
  81         sapi_module = *sf;
  82 
  83 #ifdef ZTS
  84         ts_allocate_id(&sapi_globals_id, sizeof(sapi_globals_struct), (ts_allocate_ctor) sapi_globals_ctor, (ts_allocate_dtor) sapi_globals_dtor);
  85 # ifdef PHP_WIN32
  86         _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
  87 # endif
  88 #else
  89         sapi_globals_ctor(&sapi_globals);
  90 #endif
  91 
  92 #ifdef PHP_WIN32
  93         tsrm_win32_startup();
  94 #endif
  95 
  96         reentrancy_startup();
  97 }
  98 
  99 SAPI_API void sapi_shutdown(void)
 100 {
 101 #ifdef ZTS
 102         ts_free_id(sapi_globals_id);
 103 #else
 104         sapi_globals_dtor(&sapi_globals);
 105 #endif
 106 
 107         reentrancy_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 /* {{{ proto bool header_register_callback(mixed callback)
 121    call a header function */
 122 PHP_FUNCTION(header_register_callback)
 123 {
 124         zval *callback_func;
 125 
 126         if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &callback_func) == FAILURE) {
 127                 return;
 128         }
 129 
 130         if (!zend_is_callable(callback_func, 0, NULL)) {
 131                 RETURN_FALSE;
 132         }
 133 
 134         if (Z_TYPE(SG(callback_func)) != IS_UNDEF) {
 135                 zval_ptr_dtor(&SG(callback_func));
 136                 SG(fci_cache) = empty_fcall_info_cache;
 137         }
 138 
 139         ZVAL_COPY(&SG(callback_func), callback_func);
 140 
 141         RETURN_TRUE;
 142 }
 143 /* }}} */
 144 
 145 static void sapi_run_header_callback(zval *callback)
 146 {
 147         int   error;
 148         zend_fcall_info fci;
 149         char *callback_error = NULL;
 150         zval retval;
 151 
 152         if (zend_fcall_info_init(callback, 0, &fci, &SG(fci_cache), NULL, &callback_error) == SUCCESS) {
 153                 fci.retval = &retval;
 154 
 155                 error = zend_call_function(&fci, &SG(fci_cache));
 156                 if (error == FAILURE) {
 157                         goto callback_failed;
 158                 } else {
 159                         zval_ptr_dtor(&retval);
 160                 }
 161         } else {
 162 callback_failed:
 163                 php_error_docref(NULL, E_WARNING, "Could not call the sapi_header_callback");
 164         }
 165 
 166         if (callback_error) {
 167                 efree(callback_error);
 168         }
 169 }
 170 
 171 SAPI_API void sapi_handle_post(void *arg)
 172 {
 173         if (SG(request_info).post_entry && SG(request_info).content_type_dup) {
 174                 SG(request_info).post_entry->post_handler(SG(request_info).content_type_dup, arg);
 175                 efree(SG(request_info).content_type_dup);
 176                 SG(request_info).content_type_dup = NULL;
 177         }
 178 }
 179 
 180 static void sapi_read_post_data(void)
 181 {
 182         sapi_post_entry *post_entry;
 183         uint content_type_length = (uint)strlen(SG(request_info).content_type);
 184         char *content_type = estrndup(SG(request_info).content_type, content_type_length);
 185         char *p;
 186         char oldchar=0;
 187         void (*post_reader_func)(void) = NULL;
 188 
 189 
 190         /* dedicated implementation for increased performance:
 191          * - Make the content type lowercase
 192          * - Trim descriptive data, stay with the content-type only
 193          */
 194         for (p=content_type; p<content_type+content_type_length; p++) {
 195                 switch (*p) {
 196                         case ';':
 197                         case ',':
 198                         case ' ':
 199                                 content_type_length = p-content_type;
 200                                 oldchar = *p;
 201                                 *p = 0;
 202                                 break;
 203                         default:
 204                                 *p = tolower(*p);
 205                                 break;
 206                 }
 207         }
 208 
 209         /* now try to find an appropriate POST content handler */
 210         if ((post_entry = zend_hash_str_find_ptr(&SG(known_post_content_types), content_type,
 211                         content_type_length)) != NULL) {
 212                 /* found one, register it for use */
 213                 SG(request_info).post_entry = post_entry;
 214                 post_reader_func = post_entry->post_reader;
 215         } else {
 216                 /* fallback */
 217                 SG(request_info).post_entry = NULL;
 218                 if (!sapi_module.default_post_reader) {
 219                         /* no default reader ? */
 220                         SG(request_info).content_type_dup = NULL;
 221                         sapi_module.sapi_error(E_WARNING, "Unsupported content type:  '%s'", content_type);
 222                         return;
 223                 }
 224         }
 225         if (oldchar) {
 226                 *(p-1) = oldchar;
 227         }
 228 
 229         SG(request_info).content_type_dup = content_type;
 230 
 231         if(post_reader_func) {
 232                 post_reader_func();
 233         }
 234 
 235         if(sapi_module.default_post_reader) {
 236                 sapi_module.default_post_reader();
 237         }
 238 }
 239 
 240 SAPI_API size_t sapi_read_post_block(char *buffer, size_t buflen)
 241 {
 242         size_t read_bytes;
 243 
 244         if (!sapi_module.read_post) {
 245                 return 0;
 246         }
 247 
 248         read_bytes = sapi_module.read_post(buffer, buflen);
 249 
 250         if (read_bytes > 0) {
 251                 /* gogo */
 252                 SG(read_post_bytes) += read_bytes;
 253         }
 254         if (read_bytes < buflen) {
 255                 /* done */
 256                 SG(post_read) = 1;
 257         }
 258 
 259         return read_bytes;
 260 }
 261 
 262 SAPI_API SAPI_POST_READER_FUNC(sapi_read_standard_form_data)
 263 {
 264         if ((SG(post_max_size) > 0) && (SG(request_info).content_length > SG(post_max_size))) {
 265                 php_error_docref(NULL, E_WARNING, "POST Content-Length of %pd bytes exceeds the limit of %pd bytes",
 266                                         SG(request_info).content_length, SG(post_max_size));
 267                 return;
 268         }
 269 
 270 
 271         SG(request_info).request_body = php_stream_temp_create_ex(TEMP_STREAM_DEFAULT, SAPI_POST_BLOCK_SIZE, PG(upload_tmp_dir));
 272 
 273         if (sapi_module.read_post) {
 274                 size_t read_bytes;
 275 
 276                 for (;;) {
 277                         char buffer[SAPI_POST_BLOCK_SIZE];
 278 
 279                         read_bytes = sapi_read_post_block(buffer, SAPI_POST_BLOCK_SIZE);
 280 
 281                         if (read_bytes > 0) {
 282                                 if (php_stream_write(SG(request_info).request_body, buffer, read_bytes) != read_bytes) {
 283                                         /* if parts of the stream can't be written, purge it completely */
 284                                         php_stream_truncate_set_size(SG(request_info).request_body, 0);
 285                                         php_error_docref(NULL, E_WARNING, "POST data can't be buffered; all data discarded");
 286                                         break;
 287                                 }
 288                         }
 289 
 290                         if ((SG(post_max_size) > 0) && (SG(read_post_bytes) > SG(post_max_size))) {
 291                                 php_error_docref(NULL, E_WARNING, "Actual POST length does not match Content-Length, and exceeds " ZEND_LONG_FMT " bytes", SG(post_max_size));
 292                                 break;
 293                         }
 294 
 295                         if (read_bytes < SAPI_POST_BLOCK_SIZE) {
 296                                 /* done */
 297                                 break;
 298                         }
 299                 }
 300                 php_stream_rewind(SG(request_info).request_body);
 301         }
 302 }
 303 
 304 
 305 static inline char *get_default_content_type(uint prefix_len, uint *len)
 306 {
 307         char *mimetype, *charset, *content_type;
 308         uint mimetype_len, charset_len;
 309 
 310         if (SG(default_mimetype)) {
 311                 mimetype = SG(default_mimetype);
 312                 mimetype_len = (uint)strlen(SG(default_mimetype));
 313         } else {
 314                 mimetype = SAPI_DEFAULT_MIMETYPE;
 315                 mimetype_len = sizeof(SAPI_DEFAULT_MIMETYPE) - 1;
 316         }
 317         if (SG(default_charset)) {
 318                 charset = SG(default_charset);
 319                 charset_len = (uint)strlen(SG(default_charset));
 320         } else {
 321                 charset = SAPI_DEFAULT_CHARSET;
 322                 charset_len = sizeof(SAPI_DEFAULT_CHARSET) - 1;
 323         }
 324 
 325         if (*charset && strncasecmp(mimetype, "text/", 5) == 0) {
 326                 char *p;
 327 
 328                 *len = prefix_len + mimetype_len + sizeof("; charset=") - 1 + charset_len;
 329                 content_type = (char*)emalloc(*len + 1);
 330                 p = content_type + prefix_len;
 331                 memcpy(p, mimetype, mimetype_len);
 332                 p += mimetype_len;
 333                 memcpy(p, "; charset=", sizeof("; charset=") - 1);
 334                 p += sizeof("; charset=") - 1;
 335                 memcpy(p, charset, charset_len + 1);
 336         } else {
 337                 *len = prefix_len + mimetype_len;
 338                 content_type = (char*)emalloc(*len + 1);
 339                 memcpy(content_type + prefix_len, mimetype, mimetype_len + 1);
 340         }
 341         return content_type;
 342 }
 343 
 344 
 345 SAPI_API char *sapi_get_default_content_type(void)
 346 {
 347         uint len;
 348 
 349         return get_default_content_type(0, &len);
 350 }
 351 
 352 
 353 SAPI_API void sapi_get_default_content_type_header(sapi_header_struct *default_header)
 354 {
 355     uint len;
 356 
 357         default_header->header = get_default_content_type(sizeof("Content-type: ")-1, &len);
 358         default_header->header_len = len;
 359         memcpy(default_header->header, "Content-type: ", sizeof("Content-type: ") - 1);
 360 }
 361 
 362 /*
 363  * Add charset on content-type header if the MIME type starts with
 364  * "text/", the default_charset directive is not empty and
 365  * there is not already a charset option in there.
 366  *
 367  * If "mimetype" is non-NULL, it should point to a pointer allocated
 368  * with emalloc().  If a charset is added, the string will be
 369  * re-allocated and the new length is returned.  If mimetype is
 370  * unchanged, 0 is returned.
 371  *
 372  */
 373 SAPI_API size_t sapi_apply_default_charset(char **mimetype, size_t len)
 374 {
 375         char *charset, *newtype;
 376         size_t newlen;
 377         charset = SG(default_charset) ? SG(default_charset) : SAPI_DEFAULT_CHARSET;
 378 
 379         if (*mimetype != NULL) {
 380                 if (*charset && strncmp(*mimetype, "text/", 5) == 0 && strstr(*mimetype, "charset=") == NULL) {
 381                         newlen = len + (sizeof(";charset=")-1) + strlen(charset);
 382                         newtype = emalloc(newlen + 1);
 383                         PHP_STRLCPY(newtype, *mimetype, newlen + 1, len);
 384                         strlcat(newtype, ";charset=", newlen + 1);
 385                         strlcat(newtype, charset, newlen + 1);
 386                         efree(*mimetype);
 387                         *mimetype = newtype;
 388                         return newlen;
 389                 }
 390         }
 391         return 0;
 392 }
 393 
 394 SAPI_API void sapi_activate_headers_only(void)
 395 {
 396         if (SG(request_info).headers_read == 1)
 397                 return;
 398         SG(request_info).headers_read = 1;
 399         zend_llist_init(&SG(sapi_headers).headers, sizeof(sapi_header_struct),
 400                         (void (*)(void *)) sapi_free_header, 0);
 401         SG(sapi_headers).send_default_content_type = 1;
 402 
 403         /* SG(sapi_headers).http_response_code = 200; */
 404         SG(sapi_headers).http_status_line = NULL;
 405         SG(sapi_headers).mimetype = NULL;
 406         SG(read_post_bytes) = 0;
 407         SG(request_info).request_body = NULL;
 408         SG(request_info).current_user = NULL;
 409         SG(request_info).current_user_length = 0;
 410         SG(request_info).no_headers = 0;
 411         SG(request_info).post_entry = NULL;
 412         SG(global_request_time) = 0;
 413 
 414         /*
 415          * It's possible to override this general case in the activate() callback,
 416          * if necessary.
 417          */
 418         if (SG(request_info).request_method && !strcmp(SG(request_info).request_method, "HEAD")) {
 419                 SG(request_info).headers_only = 1;
 420         } else {
 421                 SG(request_info).headers_only = 0;
 422         }
 423         if (SG(server_context)) {
 424                 SG(request_info).cookie_data = sapi_module.read_cookies();
 425                 if (sapi_module.activate) {
 426                         sapi_module.activate();
 427                 }
 428         }
 429         if (sapi_module.input_filter_init ) {
 430                 sapi_module.input_filter_init();
 431         }
 432 }
 433 
 434 /*
 435  * Called from php_request_startup() for every request.
 436  */
 437 
 438 SAPI_API void sapi_activate(void)
 439 {
 440         zend_llist_init(&SG(sapi_headers).headers, sizeof(sapi_header_struct), (void (*)(void *)) sapi_free_header, 0);
 441         SG(sapi_headers).send_default_content_type = 1;
 442 
 443         /*
 444         SG(sapi_headers).http_response_code = 200;
 445         */
 446         SG(sapi_headers).http_status_line = NULL;
 447         SG(sapi_headers).mimetype = NULL;
 448         SG(headers_sent) = 0;
 449         ZVAL_UNDEF(&SG(callback_func));
 450         SG(read_post_bytes) = 0;
 451         SG(request_info).request_body = NULL;
 452         SG(request_info).current_user = NULL;
 453         SG(request_info).current_user_length = 0;
 454         SG(request_info).no_headers = 0;
 455         SG(request_info).post_entry = NULL;
 456         SG(request_info).proto_num = 1000; /* Default to HTTP 1.0 */
 457         SG(global_request_time) = 0;
 458         SG(post_read) = 0;
 459         /* It's possible to override this general case in the activate() callback, if necessary. */
 460         if (SG(request_info).request_method && !strcmp(SG(request_info).request_method, "HEAD")) {
 461                 SG(request_info).headers_only = 1;
 462         } else {
 463                 SG(request_info).headers_only = 0;
 464         }
 465         SG(rfc1867_uploaded_files) = NULL;
 466 
 467         /* Handle request method */
 468         if (SG(server_context)) {
 469                 if (PG(enable_post_data_reading)
 470                 &&      SG(request_info).content_type
 471                 &&  SG(request_info).request_method
 472                 && !strcmp(SG(request_info).request_method, "POST")) {
 473                         /* HTTP POST may contain form data to be processed into variables
 474                          * depending on given content type */
 475                         sapi_read_post_data();
 476                 } else {
 477                         SG(request_info).content_type_dup = NULL;
 478                 }
 479 
 480                 /* Cookies */
 481                 SG(request_info).cookie_data = sapi_module.read_cookies();
 482 
 483                 if (sapi_module.activate) {
 484                         sapi_module.activate();
 485                 }
 486         }
 487         if (sapi_module.input_filter_init) {
 488                 sapi_module.input_filter_init();
 489         }
 490 }
 491 
 492 
 493 static void sapi_send_headers_free(void)
 494 {
 495         if (SG(sapi_headers).http_status_line) {
 496                 efree(SG(sapi_headers).http_status_line);
 497                 SG(sapi_headers).http_status_line = NULL;
 498         }
 499 }
 500 
 501 SAPI_API void sapi_deactivate(void)
 502 {
 503         zend_llist_destroy(&SG(sapi_headers).headers);
 504         if (SG(request_info).request_body) {
 505                 SG(request_info).request_body = NULL;
 506         } else if (SG(server_context)) {
 507                 if (!SG(post_read)) {
 508                         /* make sure we've consumed all request input data */
 509                         char dummy[SAPI_POST_BLOCK_SIZE];
 510                         size_t read_bytes;
 511 
 512                         do {
 513                                 read_bytes = sapi_read_post_block(dummy, SAPI_POST_BLOCK_SIZE);
 514                         } while (SAPI_POST_BLOCK_SIZE == read_bytes);
 515                 }
 516         }
 517         if (SG(request_info).auth_user) {
 518                 efree(SG(request_info).auth_user);
 519         }
 520         if (SG(request_info).auth_password) {
 521                 efree(SG(request_info).auth_password);
 522         }
 523         if (SG(request_info).auth_digest) {
 524                 efree(SG(request_info).auth_digest);
 525         }
 526         if (SG(request_info).content_type_dup) {
 527                 efree(SG(request_info).content_type_dup);
 528         }
 529         if (SG(request_info).current_user) {
 530                 efree(SG(request_info).current_user);
 531         }
 532         if (sapi_module.deactivate) {
 533                 sapi_module.deactivate();
 534         }
 535         if (SG(rfc1867_uploaded_files)) {
 536                 destroy_uploaded_files_hash();
 537         }
 538         if (SG(sapi_headers).mimetype) {
 539                 efree(SG(sapi_headers).mimetype);
 540                 SG(sapi_headers).mimetype = NULL;
 541         }
 542         sapi_send_headers_free();
 543         SG(sapi_started) = 0;
 544         SG(headers_sent) = 0;
 545         SG(request_info).headers_read = 0;
 546         SG(global_request_time) = 0;
 547 }
 548 
 549 
 550 SAPI_API void sapi_initialize_empty_request(void)
 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 
 559 static 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 
 575 static void sapi_update_response_code(int ncode)
 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  */
 594 static void sapi_remove_header(zend_llist *l, char *name, size_t 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 
 622 SAPI_API int sapi_add_header_ex(char *header_line, size_t header_line_len, zend_bool duplicate, zend_bool replace)
 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);
 632 
 633         if (!duplicate)
 634                 efree(header_line);
 635 
 636         return r;
 637 }
 638 
 639 static void sapi_header_add_op(sapi_header_op_enum op, sapi_header_struct *sapi_header)
 640 {
 641         if (!sapi_module.header_handler ||
 642                 (SAPI_HEADER_ADD & sapi_module.header_handler(sapi_header, op, &SG(sapi_headers)))) {
 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, (int)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 
 660 SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg)
 661 {
 662         sapi_header_struct sapi_header;
 663         char *colon_offset;
 664         char *header_line;
 665         size_t 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();
 670                 int output_start_lineno = php_output_get_start_lineno();
 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);
 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));
 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 off 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));
 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                 uint i;
 738                 for (i = 0; i < header_line_len; i++) {
 739                         /* RFC 7230 ch. 3.2.4 deprecates folding support */
 740                         if (header_line[i] == '\n' || header_line[i] == '\r') {
 741                                 efree(header_line);
 742                                 sapi_module.sapi_error(E_WARNING, "Header may not contain "
 743                                                 "more than a single header, new line detected");
 744                                 return FAILURE;
 745                         }
 746                         if (header_line[i] == '\0') {
 747                                 efree(header_line);
 748                                 sapi_module.sapi_error(E_WARNING, "Header may not contain NUL bytes");
 749                                 return FAILURE;
 750                         }
 751                 }
 752         }
 753 
 754         sapi_header.header = header_line;
 755         sapi_header.header_len = header_line_len;
 756 
 757         /* Check the header for a few cases that we have special support for in SAPI */
 758         if (header_line_len>=5
 759                 && !strncasecmp(header_line, "HTTP/", 5)) {
 760                 /* filter out the response code */
 761                 sapi_update_response_code(sapi_extract_response_code(header_line));
 762                 /* sapi_update_response_code doesn't free the status line if the code didn't change */
 763                 if (SG(sapi_headers).http_status_line) {
 764                         efree(SG(sapi_headers).http_status_line);
 765                 }
 766                 SG(sapi_headers).http_status_line = header_line;
 767                 return SUCCESS;
 768         } else {
 769                 colon_offset = strchr(header_line, ':');
 770                 if (colon_offset) {
 771                         *colon_offset = 0;
 772                         if (!strcasecmp(header_line, "Content-Type")) {
 773                                 char *ptr = colon_offset+1, *mimetype = NULL, *newheader;
 774                                 size_t len = header_line_len - (ptr - header_line), newlen;
 775                                 while (*ptr == ' ') {
 776                                         ptr++;
 777                                         len--;
 778                                 }
 779 
 780                                 /* Disable possible output compression for images */
 781                                 if (!strncmp(ptr, "image/", sizeof("image/")-1)) {
 782                                         zend_string *key = zend_string_init("zlib.output_compression", sizeof("zlib.output_compression")-1, 0);
 783                                         zend_alter_ini_entry_chars(key, "0", sizeof("0") - 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
 784                                         zend_string_release(key);
 785                                 }
 786 
 787                                 mimetype = estrdup(ptr);
 788                                 newlen = sapi_apply_default_charset(&mimetype, len);
 789                                 if (!SG(sapi_headers).mimetype){
 790                                         SG(sapi_headers).mimetype = estrdup(mimetype);
 791                                 }
 792 
 793                                 if (newlen != 0) {
 794                                         newlen += sizeof("Content-type: ");
 795                                         newheader = emalloc(newlen);
 796                                         PHP_STRLCPY(newheader, "Content-type: ", newlen, sizeof("Content-type: ")-1);
 797                                         strlcat(newheader, mimetype, newlen);
 798                                         sapi_header.header = newheader;
 799                                         sapi_header.header_len = (uint)(newlen - 1);
 800                                         efree(header_line);
 801                                 }
 802                                 efree(mimetype);
 803                                 SG(sapi_headers).send_default_content_type = 0;
 804                         } else if (!strcasecmp(header_line, "Content-Length")) {
 805                                 /* Script is setting Content-length. The script cannot reasonably
 806                                  * know the size of the message body after compression, so it's best
 807                                  * do disable compression altogether. This contributes to making scripts
 808                                  * portable between setups that have and don't have zlib compression
 809                                  * enabled globally. See req #44164 */
 810                                 zend_string *key = zend_string_init("zlib.output_compression", sizeof("zlib.output_compression")-1, 0);
 811                                 zend_alter_ini_entry_chars(key,
 812                                         "0", sizeof("0") - 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
 813                                 zend_string_release(key);
 814                         } else if (!strcasecmp(header_line, "Location")) {
 815                                 if ((SG(sapi_headers).http_response_code < 300 ||
 816                                         SG(sapi_headers).http_response_code > 399) &&
 817                                         SG(sapi_headers).http_response_code != 201) {
 818                                         /* Return a Found Redirect if one is not already specified */
 819                                         if (http_response_code) { /* user specified redirect code */
 820                                                 sapi_update_response_code(http_response_code);
 821                                         } else if (SG(request_info).proto_num > 1000 &&
 822                                            SG(request_info).request_method &&
 823                                            strcmp(SG(request_info).request_method, "HEAD") &&
 824                                            strcmp(SG(request_info).request_method, "GET")) {
 825                                                 sapi_update_response_code(303);
 826                                         } else {
 827                                                 sapi_update_response_code(302);
 828                                         }
 829                                 }
 830                         } else if (!strcasecmp(header_line, "WWW-Authenticate")) { /* HTTP Authentication */
 831                                 sapi_update_response_code(401); /* authentication-required */
 832                         }
 833                         if (sapi_header.header==header_line) {
 834                                 *colon_offset = ':';
 835                         }
 836                 }
 837         }
 838         if (http_response_code) {
 839                 sapi_update_response_code(http_response_code);
 840         }
 841         sapi_header_add_op(op, &sapi_header);
 842         return SUCCESS;
 843 }
 844 
 845 
 846 SAPI_API int sapi_send_headers(void)
 847 {
 848         int retval;
 849         int ret = FAILURE;
 850 
 851         if (SG(headers_sent) || SG(request_info).no_headers) {
 852                 return SUCCESS;
 853         }
 854 
 855         /* Success-oriented.  We set headers_sent to 1 here to avoid an infinite loop
 856          * in case of an error situation.
 857          */
 858         if (SG(sapi_headers).send_default_content_type && sapi_module.send_headers) {
 859                 sapi_header_struct default_header;
 860             uint len;
 861 
 862                 SG(sapi_headers).mimetype = get_default_content_type(0, &len);
 863                 default_header.header_len = sizeof("Content-type: ") - 1 + len;
 864                 default_header.header = emalloc(default_header.header_len + 1);
 865                 memcpy(default_header.header, "Content-type: ", sizeof("Content-type: ") - 1);
 866                 memcpy(default_header.header + sizeof("Content-type: ") - 1, SG(sapi_headers).mimetype, len + 1);
 867                 sapi_header_add_op(SAPI_HEADER_ADD, &default_header);
 868                 SG(sapi_headers).send_default_content_type = 0;
 869         }
 870 
 871         if (Z_TYPE(SG(callback_func)) != IS_UNDEF) {
 872                 zval cb;
 873                 ZVAL_COPY_VALUE(&cb, &SG(callback_func));
 874                 ZVAL_UNDEF(&SG(callback_func));
 875                 sapi_run_header_callback(&cb);
 876                 zval_ptr_dtor(&cb);
 877         }
 878 
 879         SG(headers_sent) = 1;
 880 
 881         if (sapi_module.send_headers) {
 882                 retval = sapi_module.send_headers(&SG(sapi_headers));
 883         } else {
 884                 retval = SAPI_HEADER_DO_SEND;
 885         }
 886 
 887         switch (retval) {
 888                 case SAPI_HEADER_SENT_SUCCESSFULLY:
 889                         ret = SUCCESS;
 890                         break;
 891                 case SAPI_HEADER_DO_SEND: {
 892                                 sapi_header_struct http_status_line;
 893                                 char buf[255];
 894 
 895                                 if (SG(sapi_headers).http_status_line) {
 896                                         http_status_line.header = SG(sapi_headers).http_status_line;
 897                                         http_status_line.header_len = (uint)strlen(SG(sapi_headers).http_status_line);
 898                                 } else {
 899                                         http_status_line.header = buf;
 900                                         http_status_line.header_len = slprintf(buf, sizeof(buf), "HTTP/1.0 %d X", SG(sapi_headers).http_response_code);
 901                                 }
 902                                 sapi_module.send_header(&http_status_line, SG(server_context));
 903                         }
 904                         zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t) sapi_module.send_header, SG(server_context));
 905                         if(SG(sapi_headers).send_default_content_type) {
 906                                 sapi_header_struct default_header;
 907 
 908                                 sapi_get_default_content_type_header(&default_header);
 909                                 sapi_module.send_header(&default_header, SG(server_context));
 910                                 sapi_free_header(&default_header);
 911                         }
 912                         sapi_module.send_header(NULL, SG(server_context));
 913                         ret = SUCCESS;
 914                         break;
 915                 case SAPI_HEADER_SEND_FAILED:
 916                         SG(headers_sent) = 0;
 917                         ret = FAILURE;
 918                         break;
 919         }
 920 
 921         sapi_send_headers_free();
 922 
 923         return ret;
 924 }
 925 
 926 
 927 SAPI_API int sapi_register_post_entries(sapi_post_entry *post_entries)
 928 {
 929         sapi_post_entry *p=post_entries;
 930 
 931         while (p->content_type) {
 932                 if (sapi_register_post_entry(p) == FAILURE) {
 933                         return FAILURE;
 934                 }
 935                 p++;
 936         }
 937         return SUCCESS;
 938 }
 939 
 940 
 941 SAPI_API int sapi_register_post_entry(sapi_post_entry *post_entry)
 942 {
 943         if (SG(sapi_started) && EG(current_execute_data)) {
 944                 return FAILURE;
 945         }
 946         return zend_hash_str_add_mem(&SG(known_post_content_types),
 947                         post_entry->content_type, post_entry->content_type_len,
 948                         (void *) post_entry, sizeof(sapi_post_entry)) ? SUCCESS : FAILURE;
 949 }
 950 
 951 SAPI_API void sapi_unregister_post_entry(sapi_post_entry *post_entry)
 952 {
 953         if (SG(sapi_started) && EG(current_execute_data)) {
 954                 return;
 955         }
 956         zend_hash_str_del(&SG(known_post_content_types), post_entry->content_type,
 957                         post_entry->content_type_len);
 958 }
 959 
 960 
 961 SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(void))
 962 {
 963         if (SG(sapi_started) && EG(current_execute_data)) {
 964                 return FAILURE;
 965         }
 966         sapi_module.default_post_reader = default_post_reader;
 967         return SUCCESS;
 968 }
 969 
 970 
 971 SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zval *destArray))
 972 {
 973         if (SG(sapi_started) && EG(current_execute_data)) {
 974                 return FAILURE;
 975         }
 976         sapi_module.treat_data = treat_data;
 977         return SUCCESS;
 978 }
 979 
 980 SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, size_t val_len, size_t *new_val_len), unsigned int (*input_filter_init)(void))
 981 {
 982         if (SG(sapi_started) && EG(current_execute_data)) {
 983                 return FAILURE;
 984         }
 985         sapi_module.input_filter = input_filter;
 986         sapi_module.input_filter_init = input_filter_init;
 987         return SUCCESS;
 988 }
 989 
 990 SAPI_API int sapi_flush(void)
 991 {
 992         if (sapi_module.flush) {
 993                 sapi_module.flush(SG(server_context));
 994                 return SUCCESS;
 995         } else {
 996                 return FAILURE;
 997         }
 998 }
 999 
1000 SAPI_API zend_stat_t *sapi_get_stat(void)
1001 {
1002         if (sapi_module.get_stat) {
1003                 return sapi_module.get_stat();
1004         } else {
1005                 if (!SG(request_info).path_translated || (VCWD_STAT(SG(request_info).path_translated, &SG(global_stat)) == -1)) {
1006                         return NULL;
1007                 }
1008                 return &SG(global_stat);
1009         }
1010 }
1011 
1012 SAPI_API char *sapi_getenv(char *name, size_t name_len)
1013 {
1014         if (sapi_module.getenv) {
1015                 char *value, *tmp = sapi_module.getenv(name, name_len);
1016                 if (tmp) {
1017                         value = estrdup(tmp);
1018                 } else {
1019                         return NULL;
1020                 }
1021                 if (sapi_module.input_filter) {
1022                         sapi_module.input_filter(PARSE_STRING, name, &value, strlen(value), NULL);
1023                 }
1024                 return value;
1025         }
1026         return NULL;
1027 }
1028 
1029 SAPI_API int sapi_get_fd(int *fd)
1030 {
1031         if (sapi_module.get_fd) {
1032                 return sapi_module.get_fd(fd);
1033         } else {
1034                 return FAILURE;
1035         }
1036 }
1037 
1038 SAPI_API int sapi_force_http_10(void)
1039 {
1040         if (sapi_module.force_http_10) {
1041                 return sapi_module.force_http_10();
1042         } else {
1043                 return FAILURE;
1044         }
1045 }
1046 
1047 
1048 SAPI_API int sapi_get_target_uid(uid_t *obj)
1049 {
1050         if (sapi_module.get_target_uid) {
1051                 return sapi_module.get_target_uid(obj);
1052         } else {
1053                 return FAILURE;
1054         }
1055 }
1056 
1057 SAPI_API int sapi_get_target_gid(gid_t *obj)
1058 {
1059         if (sapi_module.get_target_gid) {
1060                 return sapi_module.get_target_gid(obj);
1061         } else {
1062                 return FAILURE;
1063         }
1064 }
1065 
1066 SAPI_API double sapi_get_request_time(void)
1067 {
1068         if(SG(global_request_time)) return SG(global_request_time);
1069 
1070         if (sapi_module.get_request_time && SG(server_context)) {
1071                 SG(global_request_time) = sapi_module.get_request_time();
1072         } else {
1073                 struct timeval tp = {0};
1074                 if (!gettimeofday(&tp, NULL)) {
1075                         SG(global_request_time) = (double)(tp.tv_sec + tp.tv_usec / 1000000.00);
1076                 } else {
1077                         SG(global_request_time) = (double)time(0);
1078                 }
1079         }
1080         return SG(global_request_time);
1081 }
1082 
1083 SAPI_API void sapi_terminate_process(void) {
1084         if (sapi_module.terminate_process) {
1085                 sapi_module.terminate_process();
1086         }
1087 }
1088 
1089 /*
1090  * Local variables:
1091  * tab-width: 4
1092  * c-basic-offset: 4
1093  * End:
1094  * vim600: sw=4 ts=4 fdm=marker
1095  * vim<600: sw=4 ts=4
1096  */

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