Back to index

php5  5.3.10
SAPI.c
Go to the documentation of this file.
00001 /* 
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Original design:  Shane Caraveo <shane@caraveo.com>                  |
00016    | Authors: Andi Gutmans <andi@zend.com>                                |
00017    |          Zeev Suraski <zeev@zend.com>                                |
00018    +----------------------------------------------------------------------+
00019 */
00020 
00021 /* $Id: SAPI.c 321634 2012-01-01 13:15:04Z felipe $ */
00022 
00023 #include <ctype.h>
00024 #include <sys/stat.h>
00025 
00026 #include "php.h"
00027 #include "SAPI.h"
00028 #include "php_variables.h"
00029 #include "php_ini.h"
00030 #include "ext/standard/php_string.h"
00031 #include "ext/standard/pageinfo.h"
00032 #if (HAVE_PCRE || HAVE_BUNDLED_PCRE) && !defined(COMPILE_DL_PCRE)
00033 #include "ext/pcre/php_pcre.h"
00034 #endif
00035 #ifdef ZTS
00036 #include "TSRM.h"
00037 #endif
00038 #ifdef HAVE_SYS_TIME_H
00039 #include <sys/time.h>
00040 #endif
00041 
00042 #include "rfc1867.h"
00043 
00044 #ifdef PHP_WIN32
00045 #define STRCASECMP stricmp
00046 #else
00047 #define STRCASECMP strcasecmp
00048 #endif
00049 
00050 #include "php_content_types.h"
00051 
00052 #ifdef ZTS
00053 SAPI_API int sapi_globals_id;
00054 #else
00055 sapi_globals_struct sapi_globals;
00056 #endif
00057 
00058 static void sapi_globals_ctor(sapi_globals_struct *sapi_globals TSRMLS_DC)
00059 {
00060        memset(sapi_globals, 0, sizeof(*sapi_globals));
00061        zend_hash_init_ex(&sapi_globals->known_post_content_types, 5, NULL, NULL, 1, 0);
00062        php_setup_sapi_content_types(TSRMLS_C);
00063 }
00064 
00065 static void sapi_globals_dtor(sapi_globals_struct *sapi_globals TSRMLS_DC)
00066 {
00067        zend_hash_destroy(&sapi_globals->known_post_content_types);
00068 }
00069 
00070 /* True globals (no need for thread safety) */
00071 SAPI_API sapi_module_struct sapi_module;
00072 
00073 
00074 SAPI_API void sapi_startup(sapi_module_struct *sf)
00075 {
00076        sf->ini_entries = NULL;
00077        sapi_module = *sf;
00078 
00079 #ifdef ZTS
00080        ts_allocate_id(&sapi_globals_id, sizeof(sapi_globals_struct), (ts_allocate_ctor) sapi_globals_ctor, (ts_allocate_dtor) sapi_globals_dtor);
00081 # ifdef PHP_WIN32
00082        _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
00083 # endif
00084 #else
00085        sapi_globals_ctor(&sapi_globals);
00086 #endif
00087 
00088        virtual_cwd_startup(); /* Could use shutdown to free the main cwd but it would just slow it down for CGI */
00089 
00090 #ifdef PHP_WIN32
00091        tsrm_win32_startup();
00092 #endif
00093 
00094        reentrancy_startup();
00095 }
00096 
00097 SAPI_API void sapi_shutdown(void)
00098 {
00099 #ifdef ZTS
00100        ts_free_id(sapi_globals_id);
00101 #else
00102        sapi_globals_dtor(&sapi_globals);
00103 #endif
00104 
00105        reentrancy_shutdown();
00106 
00107        virtual_cwd_shutdown();
00108 
00109 #ifdef PHP_WIN32
00110        tsrm_win32_shutdown();
00111 #endif
00112 }
00113 
00114 
00115 SAPI_API void sapi_free_header(sapi_header_struct *sapi_header)
00116 {
00117        efree(sapi_header->header);
00118 }
00119 
00120 
00121 SAPI_API void sapi_handle_post(void *arg TSRMLS_DC)
00122 {
00123        if (SG(request_info).post_entry && SG(request_info).content_type_dup) {
00124               SG(request_info).post_entry->post_handler(SG(request_info).content_type_dup, arg TSRMLS_CC);
00125               if (SG(request_info).post_data) {
00126                      efree(SG(request_info).post_data);
00127                      SG(request_info).post_data = NULL;
00128               }
00129               efree(SG(request_info).content_type_dup);
00130               SG(request_info).content_type_dup = NULL;
00131        }
00132 }
00133 
00134 static void sapi_read_post_data(TSRMLS_D)
00135 {
00136        sapi_post_entry *post_entry;
00137        uint content_type_length = strlen(SG(request_info).content_type);
00138        char *content_type = estrndup(SG(request_info).content_type, content_type_length);
00139        char *p;
00140        char oldchar=0;
00141        void (*post_reader_func)(TSRMLS_D) = NULL;
00142 
00143 
00144        /* dedicated implementation for increased performance:
00145         * - Make the content type lowercase
00146         * - Trim descriptive data, stay with the content-type only
00147         */
00148        for (p=content_type; p<content_type+content_type_length; p++) {
00149               switch (*p) {
00150                      case ';':
00151                      case ',':
00152                      case ' ':
00153                             content_type_length = p-content_type;
00154                             oldchar = *p;
00155                             *p = 0;
00156                             break;
00157                      default:
00158                             *p = tolower(*p);
00159                             break;
00160               }
00161        }
00162 
00163        /* now try to find an appropriate POST content handler */
00164        if (zend_hash_find(&SG(known_post_content_types), content_type,
00165                      content_type_length+1, (void **) &post_entry) == SUCCESS) {
00166               /* found one, register it for use */
00167               SG(request_info).post_entry = post_entry;
00168               post_reader_func = post_entry->post_reader;
00169        } else {
00170               /* fallback */
00171               SG(request_info).post_entry = NULL;
00172               if (!sapi_module.default_post_reader) {
00173                      /* no default reader ? */
00174                      SG(request_info).content_type_dup = NULL;
00175                      sapi_module.sapi_error(E_WARNING, "Unsupported content type:  '%s'", content_type);
00176                      return;
00177               }
00178        }
00179        if (oldchar) {
00180               *(p-1) = oldchar;
00181        }
00182 
00183        SG(request_info).content_type_dup = content_type;
00184 
00185        if(post_reader_func) {
00186               post_reader_func(TSRMLS_C);
00187        }
00188 
00189        if(sapi_module.default_post_reader) {
00190               sapi_module.default_post_reader(TSRMLS_C);
00191        }
00192 }
00193 
00194 
00195 SAPI_API SAPI_POST_READER_FUNC(sapi_read_standard_form_data)
00196 {
00197        int read_bytes;
00198        int allocated_bytes=SAPI_POST_BLOCK_SIZE+1;
00199 
00200        if ((SG(post_max_size) > 0) && (SG(request_info).content_length > SG(post_max_size))) {
00201               php_error_docref(NULL TSRMLS_CC, E_WARNING, "POST Content-Length of %ld bytes exceeds the limit of %ld bytes",
00202                                    SG(request_info).content_length, SG(post_max_size));
00203               return;
00204        }
00205        SG(request_info).post_data = emalloc(allocated_bytes);
00206 
00207        for (;;) {
00208               read_bytes = sapi_module.read_post(SG(request_info).post_data+SG(read_post_bytes), SAPI_POST_BLOCK_SIZE TSRMLS_CC);
00209               if (read_bytes<=0) {
00210                      break;
00211               }
00212               SG(read_post_bytes) += read_bytes;
00213               if ((SG(post_max_size) > 0) && (SG(read_post_bytes) > SG(post_max_size))) {
00214                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Actual POST length does not match Content-Length, and exceeds %ld bytes", SG(post_max_size));
00215                      break;
00216               }
00217               if (read_bytes < SAPI_POST_BLOCK_SIZE) {
00218                      break;
00219               }
00220               if (SG(read_post_bytes)+SAPI_POST_BLOCK_SIZE >= allocated_bytes) {
00221                      allocated_bytes = SG(read_post_bytes)+SAPI_POST_BLOCK_SIZE+1;
00222                      SG(request_info).post_data = erealloc(SG(request_info).post_data, allocated_bytes);
00223               }
00224        }
00225        SG(request_info).post_data[SG(read_post_bytes)] = 0;  /* terminating NULL */
00226        SG(request_info).post_data_length = SG(read_post_bytes);
00227 }
00228 
00229 
00230 SAPI_API char *sapi_get_default_content_type(TSRMLS_D)
00231 {
00232        char *mimetype, *charset, *content_type;
00233 
00234        mimetype = SG(default_mimetype) ? SG(default_mimetype) : SAPI_DEFAULT_MIMETYPE;
00235        charset = SG(default_charset) ? SG(default_charset) : SAPI_DEFAULT_CHARSET;
00236 
00237        if (strncasecmp(mimetype, "text/", 5) == 0 && *charset) {
00238               int len = strlen(mimetype) + sizeof("; charset=") + strlen(charset); /* sizeof() includes \0 */
00239               content_type = emalloc(len);
00240               snprintf(content_type, len, "%s; charset=%s", mimetype, charset);
00241        } else {
00242               content_type = estrdup(mimetype);
00243        }
00244        return content_type;
00245 }
00246 
00247 
00248 SAPI_API void sapi_get_default_content_type_header(sapi_header_struct *default_header TSRMLS_DC)
00249 {
00250        char *default_content_type = sapi_get_default_content_type(TSRMLS_C);
00251        int default_content_type_len = strlen(default_content_type);
00252 
00253        default_header->header_len = (sizeof("Content-type: ")-1) + default_content_type_len;
00254        default_header->header = emalloc(default_header->header_len+1);
00255        memcpy(default_header->header, "Content-type: ", sizeof("Content-type: "));
00256        memcpy(default_header->header+sizeof("Content-type: ")-1, default_content_type, default_content_type_len);
00257        default_header->header[default_header->header_len] = 0;
00258        efree(default_content_type);
00259 }
00260 
00261 /*
00262  * Add charset on content-type header if the MIME type starts with
00263  * "text/", the default_charset directive is not empty and
00264  * there is not already a charset option in there.
00265  *
00266  * If "mimetype" is non-NULL, it should point to a pointer allocated
00267  * with emalloc().  If a charset is added, the string will be
00268  * re-allocated and the new length is returned.  If mimetype is
00269  * unchanged, 0 is returned.
00270  *
00271  */
00272 SAPI_API size_t sapi_apply_default_charset(char **mimetype, size_t len TSRMLS_DC)
00273 {
00274        char *charset, *newtype;
00275        size_t newlen;
00276        charset = SG(default_charset) ? SG(default_charset) : SAPI_DEFAULT_CHARSET;
00277 
00278        if (*mimetype != NULL) {
00279               if (*charset && strncmp(*mimetype, "text/", 5) == 0 && strstr(*mimetype, "charset=") == NULL) {
00280                      newlen = len + (sizeof(";charset=")-1) + strlen(charset);
00281                      newtype = emalloc(newlen + 1);
00282                      PHP_STRLCPY(newtype, *mimetype, newlen + 1, len);
00283                      strlcat(newtype, ";charset=", newlen + 1);
00284                      strlcat(newtype, charset, newlen + 1);
00285                      efree(*mimetype);
00286                      *mimetype = newtype;
00287                      return newlen;
00288               }
00289        }
00290        return 0;
00291 }
00292 
00293 SAPI_API void sapi_activate_headers_only(TSRMLS_D)
00294 {
00295        if (SG(request_info).headers_read == 1)
00296               return;
00297        SG(request_info).headers_read = 1;
00298        zend_llist_init(&SG(sapi_headers).headers, sizeof(sapi_header_struct), 
00299                      (void (*)(void *)) sapi_free_header, 0);
00300        SG(sapi_headers).send_default_content_type = 1;
00301 
00302        /* SG(sapi_headers).http_response_code = 200; */ 
00303        SG(sapi_headers).http_status_line = NULL;
00304        SG(sapi_headers).mimetype = NULL;
00305        SG(read_post_bytes) = 0;
00306        SG(request_info).post_data = NULL;
00307        SG(request_info).raw_post_data = NULL;
00308        SG(request_info).current_user = NULL;
00309        SG(request_info).current_user_length = 0;
00310        SG(request_info).no_headers = 0;
00311        SG(request_info).post_entry = NULL;
00312        SG(global_request_time) = 0;
00313 
00314        /*
00315         * It's possible to override this general case in the activate() callback, 
00316         * if necessary.
00317         */
00318        if (SG(request_info).request_method && !strcmp(SG(request_info).request_method, "HEAD")) {
00319               SG(request_info).headers_only = 1;
00320        } else {
00321               SG(request_info).headers_only = 0;
00322        }
00323        if (SG(server_context)) {
00324               SG(request_info).cookie_data = sapi_module.read_cookies(TSRMLS_C);
00325               if (sapi_module.activate) {
00326                      sapi_module.activate(TSRMLS_C);
00327               }
00328        }
00329        if (sapi_module.input_filter_init ) {
00330               sapi_module.input_filter_init(TSRMLS_C);
00331        }
00332 }
00333 
00334 /*
00335  * Called from php_request_startup() for every request.
00336  */
00337 
00338 SAPI_API void sapi_activate(TSRMLS_D)
00339 {
00340        zend_llist_init(&SG(sapi_headers).headers, sizeof(sapi_header_struct), (void (*)(void *)) sapi_free_header, 0);
00341        SG(sapi_headers).send_default_content_type = 1;
00342 
00343        /*
00344        SG(sapi_headers).http_response_code = 200;
00345        */
00346        SG(sapi_headers).http_status_line = NULL;
00347        SG(sapi_headers).mimetype = NULL;
00348        SG(headers_sent) = 0;
00349        SG(read_post_bytes) = 0;
00350        SG(request_info).post_data = NULL;
00351        SG(request_info).raw_post_data = NULL;
00352        SG(request_info).current_user = NULL;
00353        SG(request_info).current_user_length = 0;
00354        SG(request_info).no_headers = 0;
00355        SG(request_info).post_entry = NULL;
00356        SG(request_info).proto_num = 1000; /* Default to HTTP 1.0 */
00357        SG(global_request_time) = 0;
00358 
00359        /* It's possible to override this general case in the activate() callback, if
00360         * necessary.
00361         */
00362        if (SG(request_info).request_method && !strcmp(SG(request_info).request_method, "HEAD")) {
00363               SG(request_info).headers_only = 1;
00364        } else {
00365               SG(request_info).headers_only = 0;
00366        }
00367        SG(rfc1867_uploaded_files) = NULL;
00368 
00369        /* handle request mehtod */
00370        if (SG(server_context)) {
00371               if ( SG(request_info).request_method) {
00372                      if(!strcmp(SG(request_info).request_method, "POST")
00373                         && (SG(request_info).content_type)) {
00374                             /* HTTP POST -> may contain form data to be read into variables
00375                                depending on content type given
00376                             */
00377                             sapi_read_post_data(TSRMLS_C);
00378                      } else {
00379                             /* any other method with content payload will fill 
00380                                $HTTP_RAW_POST_DATA if enabled by always_populate_raw_post_data 
00381                                it is up to the webserver to decide whether to allow a method or not
00382                             */
00383                             SG(request_info).content_type_dup = NULL;
00384                             if(sapi_module.default_post_reader) {
00385                                    sapi_module.default_post_reader(TSRMLS_C);
00386                             }
00387                      }
00388               } else {
00389                      SG(request_info).content_type_dup = NULL;
00390               }
00391 
00392               /* Cookies */
00393               SG(request_info).cookie_data = sapi_module.read_cookies(TSRMLS_C);
00394               if (sapi_module.activate) {
00395                      sapi_module.activate(TSRMLS_C);
00396               }
00397        }
00398        if (sapi_module.input_filter_init ) {
00399               sapi_module.input_filter_init(TSRMLS_C);
00400        }
00401 }
00402 
00403 
00404 static void sapi_send_headers_free(TSRMLS_D)
00405 {
00406        if (SG(sapi_headers).http_status_line) {
00407               efree(SG(sapi_headers).http_status_line);
00408               SG(sapi_headers).http_status_line = NULL;
00409        }
00410 }
00411        
00412 SAPI_API void sapi_deactivate(TSRMLS_D)
00413 {
00414        zend_llist_destroy(&SG(sapi_headers).headers);
00415        if (SG(request_info).post_data) {
00416               efree(SG(request_info).post_data);
00417        }  else       if (SG(server_context)) {
00418               if(sapi_module.read_post) { 
00419                      /* make sure we've consumed all request input data */
00420                      char dummy[SAPI_POST_BLOCK_SIZE];
00421                      int read_bytes;
00422 
00423                      while((read_bytes = sapi_module.read_post(dummy, sizeof(dummy)-1 TSRMLS_CC)) > 0) {
00424                             SG(read_post_bytes) += read_bytes;
00425                      }
00426               }
00427        }
00428        if (SG(request_info).raw_post_data) {
00429               efree(SG(request_info).raw_post_data);
00430        } 
00431        if (SG(request_info).auth_user) {
00432               efree(SG(request_info).auth_user);
00433        }
00434        if (SG(request_info).auth_password) {
00435               efree(SG(request_info).auth_password);
00436        }
00437        if (SG(request_info).auth_digest) {
00438               efree(SG(request_info).auth_digest);
00439        }
00440        if (SG(request_info).content_type_dup) {
00441               efree(SG(request_info).content_type_dup);
00442        }
00443        if (SG(request_info).current_user) {
00444               efree(SG(request_info).current_user);
00445        }
00446        if (sapi_module.deactivate) {
00447               sapi_module.deactivate(TSRMLS_C);
00448        }
00449        if (SG(rfc1867_uploaded_files)) {
00450               destroy_uploaded_files_hash(TSRMLS_C);
00451        }
00452        if (SG(sapi_headers).mimetype) {
00453               efree(SG(sapi_headers).mimetype);
00454               SG(sapi_headers).mimetype = NULL;
00455        }
00456        sapi_send_headers_free(TSRMLS_C);
00457        SG(sapi_started) = 0;
00458        SG(headers_sent) = 0;
00459        SG(request_info).headers_read = 0;
00460        SG(global_request_time) = 0;
00461 }
00462 
00463 
00464 SAPI_API void sapi_initialize_empty_request(TSRMLS_D)
00465 {
00466        SG(server_context) = NULL;
00467        SG(request_info).request_method = NULL;
00468        SG(request_info).auth_digest = SG(request_info).auth_user = SG(request_info).auth_password = NULL;
00469        SG(request_info).content_type_dup = NULL;
00470 }
00471 
00472 
00473 static int sapi_extract_response_code(const char *header_line)
00474 {
00475        int code = 200;
00476        const char *ptr;
00477 
00478        for (ptr = header_line; *ptr; ptr++) {
00479               if (*ptr == ' ' && *(ptr + 1) != ' ') {
00480                      code = atoi(ptr + 1);
00481                      break;
00482               }
00483        }
00484        
00485        return code;
00486 }
00487 
00488 
00489 static void sapi_update_response_code(int ncode TSRMLS_DC)
00490 {
00491        /* if the status code did not change, we do not want
00492           to change the status line, and no need to change the code */
00493        if (SG(sapi_headers).http_response_code == ncode) {
00494               return;
00495        }
00496 
00497        if (SG(sapi_headers).http_status_line) {
00498               efree(SG(sapi_headers).http_status_line);
00499               SG(sapi_headers).http_status_line = NULL;
00500        }
00501        SG(sapi_headers).http_response_code = ncode;
00502 }
00503 
00504 static int sapi_find_matching_header(void *element1, void *element2)
00505 {
00506        int len = strlen((char*)element2);
00507        return strncasecmp(((sapi_header_struct*)element1)->header, (char*)element2, len) == 0 && ((sapi_header_struct*)element1)->header[len] == ':';
00508 }
00509 
00510 SAPI_API int sapi_add_header_ex(char *header_line, uint header_line_len, zend_bool duplicate, zend_bool replace TSRMLS_DC)
00511 {
00512        sapi_header_line ctr = {0};
00513        int r;
00514        
00515        ctr.line = header_line;
00516        ctr.line_len = header_line_len;
00517 
00518        r = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD,
00519                      &ctr TSRMLS_CC);
00520 
00521        if (!duplicate)
00522               efree(header_line);
00523 
00524        return r;
00525 }
00526 
00527 SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC)
00528 {
00529        int retval;
00530        sapi_header_struct sapi_header;
00531        char *colon_offset;
00532        long myuid = 0L;
00533        char *header_line;
00534        uint header_line_len;
00535        int http_response_code;
00536        
00537        if (SG(headers_sent) && !SG(request_info).no_headers) {
00538               char *output_start_filename = php_get_output_start_filename(TSRMLS_C);
00539               int output_start_lineno = php_get_output_start_lineno(TSRMLS_C);
00540 
00541               if (output_start_filename) {
00542                      sapi_module.sapi_error(E_WARNING, "Cannot modify header information - headers already sent by (output started at %s:%d)",
00543                             output_start_filename, output_start_lineno);
00544               } else {
00545                      sapi_module.sapi_error(E_WARNING, "Cannot modify header information - headers already sent");
00546               }
00547               return FAILURE;
00548        }
00549 
00550        switch (op) {
00551               case SAPI_HEADER_SET_STATUS:
00552                      sapi_update_response_code((int)(zend_intptr_t) arg TSRMLS_CC);
00553                      return SUCCESS;
00554 
00555               case SAPI_HEADER_ADD:
00556               case SAPI_HEADER_REPLACE:
00557               case SAPI_HEADER_DELETE: {
00558                             sapi_header_line *p = arg;
00559 
00560                             if (!p->line || !p->line_len) {
00561                                    return FAILURE;
00562                             }
00563                             header_line = p->line;
00564                             header_line_len = p->line_len;
00565                             http_response_code = p->response_code;
00566                             break;
00567                      }
00568 
00569               case SAPI_HEADER_DELETE_ALL:
00570                      if (sapi_module.header_handler) {
00571                             sapi_module.header_handler(&sapi_header, op, &SG(sapi_headers) TSRMLS_CC);
00572                      }
00573                      zend_llist_clean(&SG(sapi_headers).headers);
00574                      return SUCCESS;
00575 
00576               default:
00577                      return FAILURE;
00578        }
00579 
00580        header_line = estrndup(header_line, header_line_len);
00581 
00582        /* cut of trailing spaces, linefeeds and carriage-returns */
00583        while(header_line_len && isspace(header_line[header_line_len-1])) 
00584                 header_line[--header_line_len]='\0';
00585        
00586        if (op == SAPI_HEADER_DELETE) {
00587               if (strchr(header_line, ':')) {
00588                      efree(header_line);
00589                      sapi_module.sapi_error(E_WARNING, "Header to delete may not contain colon.");
00590                      return FAILURE;
00591               }
00592        } else {
00593               /* new line safety check */
00594               char *s = header_line, *e = header_line + header_line_len, *p;
00595               while (s < e && (p = memchr(s, '\n', (e - s)))) {
00596                      if (*(p + 1) == ' ' || *(p + 1) == '\t') {
00597                             s = p + 1;
00598                             continue;
00599                      }
00600                      efree(header_line);
00601                      sapi_module.sapi_error(E_WARNING, "Header may not contain more than a single header, new line detected.");
00602                      return FAILURE;
00603               }
00604        }
00605 
00606        sapi_header.header = header_line;
00607        sapi_header.header_len = header_line_len;
00608 
00609        if (op == SAPI_HEADER_DELETE) {
00610               if (sapi_module.header_handler) {
00611                      sapi_module.header_handler(&sapi_header, op, &SG(sapi_headers) TSRMLS_CC);
00612               }
00613               zend_llist_del_element(&SG(sapi_headers).headers, sapi_header.header, (int(*)(void*, void*))sapi_find_matching_header);
00614               sapi_free_header(&sapi_header);
00615               return SUCCESS;
00616        }
00617 
00618        /* Check the header for a few cases that we have special support for in SAPI */
00619        if (header_line_len>=5 
00620               && !strncasecmp(header_line, "HTTP/", 5)) {
00621               /* filter out the response code */
00622               sapi_update_response_code(sapi_extract_response_code(header_line) TSRMLS_CC);
00623               /* sapi_update_response_code doesn't free the status line if the code didn't change */
00624               if (SG(sapi_headers).http_status_line) {
00625                      efree(SG(sapi_headers).http_status_line);
00626               }
00627               SG(sapi_headers).http_status_line = header_line;
00628               return SUCCESS;
00629        } else {
00630               colon_offset = strchr(header_line, ':');
00631               if (colon_offset) {
00632                      *colon_offset = 0;
00633                      if (!STRCASECMP(header_line, "Content-Type")) {
00634                             char *ptr = colon_offset+1, *mimetype = NULL, *newheader;
00635                             size_t len = header_line_len - (ptr - header_line), newlen;
00636                             while (*ptr == ' ') {
00637                                    ptr++;
00638                                    len--;
00639                             }
00640 
00641                             /* Disable possible output compression for images */
00642                             if (!strncmp(ptr, "image/", sizeof("image/")-1)) {
00643                                    zend_alter_ini_entry("zlib.output_compression", sizeof("zlib.output_compression"), "0", sizeof("0") - 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
00644                             }
00645 
00646                             mimetype = estrdup(ptr);
00647                             newlen = sapi_apply_default_charset(&mimetype, len TSRMLS_CC);
00648                             if (!SG(sapi_headers).mimetype){
00649                                    SG(sapi_headers).mimetype = estrdup(mimetype);
00650                             }
00651 
00652                             if (newlen != 0) {
00653                                    newlen += sizeof("Content-type: ");
00654                                    newheader = emalloc(newlen);
00655                                    PHP_STRLCPY(newheader, "Content-type: ", newlen, sizeof("Content-type: ")-1);
00656                                    strlcat(newheader, mimetype, newlen);
00657                                    sapi_header.header = newheader;
00658                                    sapi_header.header_len = newlen - 1;
00659                                    efree(header_line);
00660                             }
00661                             efree(mimetype);
00662                             SG(sapi_headers).send_default_content_type = 0;
00663                      } else if (!STRCASECMP(header_line, "Location")) {
00664                             if ((SG(sapi_headers).http_response_code < 300 ||
00665                                    SG(sapi_headers).http_response_code > 307) &&
00666                                    SG(sapi_headers).http_response_code != 201) {
00667                                    /* Return a Found Redirect if one is not already specified */
00668                                    if (http_response_code) { /* user specified redirect code */
00669                                           sapi_update_response_code(http_response_code TSRMLS_CC);
00670                                    } else if (SG(request_info).proto_num > 1000 && 
00671                                       SG(request_info).request_method && 
00672                                       strcmp(SG(request_info).request_method, "HEAD") &&
00673                                       strcmp(SG(request_info).request_method, "GET")) {
00674                                           sapi_update_response_code(303 TSRMLS_CC);
00675                                    } else {
00676                                           sapi_update_response_code(302 TSRMLS_CC);
00677                                    }
00678                             }
00679                      } else if (!STRCASECMP(header_line, "WWW-Authenticate")) { /* HTTP Authentication */
00680 
00681                             sapi_update_response_code(401 TSRMLS_CC); /* authentication-required */
00682 
00683                             if(PG(safe_mode)) 
00684 #if (HAVE_PCRE || HAVE_BUNDLED_PCRE) && !defined(COMPILE_DL_PCRE)
00685                             {
00686                                    zval *repl_temp;
00687                                    char *ptr = colon_offset+1, *result, *newheader;
00688                                    int ptr_len=0, result_len = 0, newlen = 0;
00689 
00690                                    /* skip white space */
00691                                    while (isspace(*ptr)) {
00692                                           ptr++;
00693                                    }
00694 
00695                                    myuid = php_getuid();
00696 
00697                                    ptr_len = strlen(ptr);
00698                                    MAKE_STD_ZVAL(repl_temp);
00699                                    Z_TYPE_P(repl_temp) = IS_STRING;
00700                                    Z_STRLEN_P(repl_temp) = spprintf(&Z_STRVAL_P(repl_temp), 0, "realm=\"\\1-%ld\"", myuid);
00701                                    /* Modify quoted realm value */
00702                                    result = php_pcre_replace("/realm=\"(.*?)\"/i", 16,
00703                                                                               ptr, ptr_len,
00704                                                                               repl_temp,
00705                                                                               0, &result_len, -1, NULL TSRMLS_CC);
00706                                    if(result_len==ptr_len) {
00707                                           efree(result);
00708                                           efree(Z_STRVAL_P(repl_temp));
00709                                           Z_STRLEN_P(repl_temp) = spprintf(&Z_STRVAL_P(repl_temp), 0, "realm=\\1-%ld\\2", myuid);
00710                                           /* modify unquoted realm value */
00711                                           result = php_pcre_replace("/realm=([^\\s]+)(.*)/i", 21, 
00712                                                                                     ptr, ptr_len,
00713                                                                                     repl_temp,
00714                                                                                     0, &result_len, -1, NULL TSRMLS_CC);
00715                                           if(result_len==ptr_len) {
00716                                                  char *lower_temp = estrdup(ptr);   
00717                                                  char conv_temp[32];
00718                                                  int conv_len;
00719 
00720                                                  php_strtolower(lower_temp,strlen(lower_temp));
00721                                                  /* If there is no realm string at all, append one */
00722                                                  if(!strstr(lower_temp,"realm")) {
00723                                                         efree(result);
00724                                                         conv_len = slprintf(conv_temp, sizeof(conv_temp), " realm=\"%ld\"",myuid);
00725                                                         result = emalloc(ptr_len+conv_len+1);
00726                                                         result_len = ptr_len+conv_len;
00727                                                         memcpy(result, ptr, ptr_len);      
00728                                                         memcpy(result+ptr_len, conv_temp, conv_len);
00729                                                         *(result+ptr_len+conv_len) = '\0';
00730                                                  }
00731                                                  efree(lower_temp);
00732                                           }
00733                                    }
00734                                    newlen = spprintf(&newheader, 0, "WWW-Authenticate: %s", result);
00735                                    efree(header_line);
00736                                    sapi_header.header = newheader;
00737                                    sapi_header.header_len = newlen;
00738                                    efree(result);
00739                                    efree(Z_STRVAL_P(repl_temp));
00740                                    efree(repl_temp);
00741                             } 
00742 #else
00743                             {
00744                                    myuid = php_getuid();
00745                                    efree(header_line);
00746                                    sapi_header.header_len = spprintf(&sapi_header.header, 0, "WWW-Authenticate: Basic realm=\"%ld\"", myuid);
00747                             }
00748 #endif
00749                      }
00750                      if (sapi_header.header==header_line) {
00751                             *colon_offset = ':';
00752                      }
00753               }
00754        }
00755        if (http_response_code) {
00756               sapi_update_response_code(http_response_code TSRMLS_CC);
00757        }
00758        if (sapi_module.header_handler) {
00759               retval = sapi_module.header_handler(&sapi_header, op, &SG(sapi_headers) TSRMLS_CC);
00760        } else {
00761               retval = SAPI_HEADER_ADD;
00762        }
00763        if (retval & SAPI_HEADER_ADD) {
00764               /* in replace mode first remove the header if it already exists in the headers llist */
00765               if (op == SAPI_HEADER_REPLACE) {
00766                      colon_offset = strchr(sapi_header.header, ':');
00767                      if (colon_offset) {
00768                             char sav;
00769                             sav = *colon_offset;
00770                             *colon_offset = 0;
00771                             zend_llist_del_element(&SG(sapi_headers).headers, sapi_header.header, (int(*)(void*, void*))sapi_find_matching_header);
00772                             *colon_offset = sav;
00773                      }
00774               }
00775 
00776               zend_llist_add_element(&SG(sapi_headers).headers, (void *) &sapi_header);
00777        } else {
00778               sapi_free_header(&sapi_header);
00779        }
00780        return SUCCESS;
00781 }
00782 
00783 
00784 SAPI_API int sapi_send_headers(TSRMLS_D)
00785 {
00786        int retval;
00787        int ret = FAILURE;
00788 
00789        if (SG(headers_sent) || SG(request_info).no_headers) {
00790               return SUCCESS;
00791        }
00792 
00793        /* Success-oriented.  We set headers_sent to 1 here to avoid an infinite loop
00794         * in case of an error situation.
00795         */
00796        if (SG(sapi_headers).send_default_content_type && sapi_module.send_headers) {
00797               sapi_header_struct default_header;
00798               sapi_get_default_content_type_header(&default_header TSRMLS_CC);
00799               sapi_add_header_ex(default_header.header, default_header.header_len, 0, 0 TSRMLS_CC);
00800        }
00801 
00802        SG(headers_sent) = 1;
00803 
00804        if (sapi_module.send_headers) {
00805               retval = sapi_module.send_headers(&SG(sapi_headers) TSRMLS_CC);
00806        } else {
00807               retval = SAPI_HEADER_DO_SEND;
00808        }
00809 
00810        switch (retval) {
00811               case SAPI_HEADER_SENT_SUCCESSFULLY:
00812                      ret = SUCCESS;
00813                      break;
00814               case SAPI_HEADER_DO_SEND: {
00815                             sapi_header_struct http_status_line;
00816                             char buf[255];
00817 
00818                             if (SG(sapi_headers).http_status_line) {
00819                                    http_status_line.header = SG(sapi_headers).http_status_line;
00820                                    http_status_line.header_len = strlen(SG(sapi_headers).http_status_line);
00821                             } else {
00822                                    http_status_line.header = buf;
00823                                    http_status_line.header_len = slprintf(buf, sizeof(buf), "HTTP/1.0 %d X", SG(sapi_headers).http_response_code);
00824                             }
00825                             sapi_module.send_header(&http_status_line, SG(server_context) TSRMLS_CC);
00826                      }
00827                      zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t) sapi_module.send_header, SG(server_context) TSRMLS_CC);
00828                      if(SG(sapi_headers).send_default_content_type) {
00829                             sapi_header_struct default_header;
00830 
00831                             sapi_get_default_content_type_header(&default_header TSRMLS_CC);
00832                             sapi_module.send_header(&default_header, SG(server_context) TSRMLS_CC);
00833                             sapi_free_header(&default_header);
00834                      }
00835                      sapi_module.send_header(NULL, SG(server_context) TSRMLS_CC);
00836                      ret = SUCCESS;
00837                      break;
00838               case SAPI_HEADER_SEND_FAILED:
00839                      SG(headers_sent) = 0;
00840                      ret = FAILURE;
00841                      break;
00842        }
00843 
00844        sapi_send_headers_free(TSRMLS_C);
00845 
00846        return ret;
00847 }
00848 
00849 
00850 SAPI_API int sapi_register_post_entries(sapi_post_entry *post_entries TSRMLS_DC)
00851 {
00852        sapi_post_entry *p=post_entries;
00853 
00854        while (p->content_type) {
00855               if (sapi_register_post_entry(p TSRMLS_CC) == FAILURE) {
00856                      return FAILURE;
00857               }
00858               p++;
00859        }
00860        return SUCCESS;
00861 }
00862 
00863 
00864 SAPI_API int sapi_register_post_entry(sapi_post_entry *post_entry TSRMLS_DC)
00865 {
00866        if (SG(sapi_started) && EG(in_execution)) {
00867               return FAILURE;
00868        }
00869        return zend_hash_add(&SG(known_post_content_types),
00870                      post_entry->content_type, post_entry->content_type_len+1,
00871                      (void *) post_entry, sizeof(sapi_post_entry), NULL);
00872 }
00873 
00874 SAPI_API void sapi_unregister_post_entry(sapi_post_entry *post_entry TSRMLS_DC)
00875 {
00876        if (SG(sapi_started) && EG(in_execution)) {
00877               return;
00878        }
00879        zend_hash_del(&SG(known_post_content_types), post_entry->content_type,
00880                      post_entry->content_type_len+1);
00881 }
00882 
00883 
00884 SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(TSRMLS_D))
00885 {
00886        TSRMLS_FETCH();
00887        if (SG(sapi_started) && EG(in_execution)) {
00888               return FAILURE;
00889        }
00890        sapi_module.default_post_reader = default_post_reader;
00891        return SUCCESS;
00892 }
00893 
00894 
00895 SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zval *destArray TSRMLS_DC))
00896 {
00897        TSRMLS_FETCH();
00898        if (SG(sapi_started) && EG(in_execution)) {
00899               return FAILURE;
00900        }
00901        sapi_module.treat_data = treat_data;
00902        return SUCCESS;
00903 }
00904 
00905 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))
00906 {
00907        TSRMLS_FETCH();
00908        if (SG(sapi_started) && EG(in_execution)) {
00909               return FAILURE;
00910        }
00911        sapi_module.input_filter = input_filter;
00912        sapi_module.input_filter_init = input_filter_init;
00913        return SUCCESS;
00914 }
00915 
00916 SAPI_API int sapi_flush(TSRMLS_D)
00917 {
00918        if (sapi_module.flush) {
00919               sapi_module.flush(SG(server_context));
00920               return SUCCESS;
00921        } else {
00922               return FAILURE;
00923        }
00924 }
00925 
00926 SAPI_API struct stat *sapi_get_stat(TSRMLS_D)
00927 {
00928        if (sapi_module.get_stat) {
00929               return sapi_module.get_stat(TSRMLS_C);
00930        } else {
00931               if (!SG(request_info).path_translated || (VCWD_STAT(SG(request_info).path_translated, &SG(global_stat)) == -1)) {
00932                      return NULL;
00933               }
00934               return &SG(global_stat);
00935        }
00936 }
00937 
00938 SAPI_API char *sapi_getenv(char *name, size_t name_len TSRMLS_DC)
00939 {
00940        if (sapi_module.getenv) { 
00941               char *value, *tmp = sapi_module.getenv(name, name_len TSRMLS_CC);
00942               if (tmp) {
00943                      value = estrdup(tmp);
00944               } else {
00945                      return NULL;
00946               }
00947               sapi_module.input_filter(PARSE_ENV, name, &value, strlen(value), NULL TSRMLS_CC);
00948               return value;
00949        }
00950        return NULL;
00951 }
00952 
00953 SAPI_API int sapi_get_fd(int *fd TSRMLS_DC)
00954 {
00955        if (sapi_module.get_fd) {
00956               return sapi_module.get_fd(fd TSRMLS_CC);
00957        } else {
00958               return FAILURE;
00959        }
00960 }
00961 
00962 SAPI_API int sapi_force_http_10(TSRMLS_D)
00963 {
00964        if (sapi_module.force_http_10) {
00965               return sapi_module.force_http_10(TSRMLS_C);
00966        } else {
00967               return FAILURE;
00968        }
00969 }
00970 
00971 
00972 SAPI_API int sapi_get_target_uid(uid_t *obj TSRMLS_DC)
00973 {
00974        if (sapi_module.get_target_uid) {
00975               return sapi_module.get_target_uid(obj TSRMLS_CC);
00976        } else {
00977               return FAILURE;
00978        }
00979 }
00980 
00981 SAPI_API int sapi_get_target_gid(gid_t *obj TSRMLS_DC)
00982 {
00983        if (sapi_module.get_target_gid) {
00984               return sapi_module.get_target_gid(obj TSRMLS_CC);
00985        } else {
00986               return FAILURE;
00987        }
00988 }
00989 
00990 SAPI_API time_t sapi_get_request_time(TSRMLS_D)
00991 {
00992        if(SG(global_request_time)) return SG(global_request_time);
00993 
00994        if (sapi_module.get_request_time && SG(server_context)) {
00995               SG(global_request_time) = sapi_module.get_request_time(TSRMLS_C);
00996        } else {
00997               SG(global_request_time) = time(0);
00998        }
00999        return SG(global_request_time);
01000 }
01001 
01002 SAPI_API void sapi_terminate_process(TSRMLS_D) {
01003        if (sapi_module.terminate_process) {
01004               sapi_module.terminate_process(TSRMLS_C);
01005        }
01006 }
01007 
01008 /*
01009  * Local variables:
01010  * tab-width: 4
01011  * c-basic-offset: 4
01012  * End:
01013  * vim600: sw=4 ts=4 fdm=marker
01014  * vim<600: sw=4 ts=4
01015  */