Annotation of embedaddon/php/main/SAPI.c, revision 1.1.1.1

1.1       misho       1: /* 
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
                      5:    | Copyright (c) 1997-2012 The PHP Group                                |
                      6:    +----------------------------------------------------------------------+
                      7:    | This source file is subject to version 3.01 of the PHP license,      |
                      8:    | that is bundled with this package in the file LICENSE, and is        |
                      9:    | available through the world-wide-web at the following url:           |
                     10:    | http://www.php.net/license/3_01.txt                                  |
                     11:    | If you did not receive a copy of the PHP license and are unable to   |
                     12:    | obtain it through the world-wide-web, please send a note to          |
                     13:    | license@php.net so we can mail you a copy immediately.               |
                     14:    +----------------------------------------------------------------------+
                     15:    | Original design:  Shane Caraveo <shane@caraveo.com>                  |
                     16:    | Authors: Andi Gutmans <andi@zend.com>                                |
                     17:    |          Zeev Suraski <zeev@zend.com>                                |
                     18:    +----------------------------------------------------------------------+
                     19: */
                     20: 
                     21: /* $Id: SAPI.c 321634 2012-01-01 13:15:04Z felipe $ */
                     22: 
                     23: #include <ctype.h>
                     24: #include <sys/stat.h>
                     25: 
                     26: #include "php.h"
                     27: #include "SAPI.h"
                     28: #include "php_variables.h"
                     29: #include "php_ini.h"
                     30: #include "ext/standard/php_string.h"
                     31: #include "ext/standard/pageinfo.h"
                     32: #if (HAVE_PCRE || HAVE_BUNDLED_PCRE) && !defined(COMPILE_DL_PCRE)
                     33: #include "ext/pcre/php_pcre.h"
                     34: #endif
                     35: #ifdef ZTS
                     36: #include "TSRM.h"
                     37: #endif
                     38: #ifdef HAVE_SYS_TIME_H
                     39: #include <sys/time.h>
                     40: #endif
                     41: 
                     42: #include "rfc1867.h"
                     43: 
                     44: #ifdef PHP_WIN32
                     45: #define STRCASECMP stricmp
                     46: #else
                     47: #define STRCASECMP strcasecmp
                     48: #endif
                     49: 
                     50: #include "php_content_types.h"
                     51: 
                     52: #ifdef ZTS
                     53: SAPI_API int sapi_globals_id;
                     54: #else
                     55: sapi_globals_struct sapi_globals;
                     56: #endif
                     57: 
                     58: static void sapi_globals_ctor(sapi_globals_struct *sapi_globals TSRMLS_DC)
                     59: {
                     60:        memset(sapi_globals, 0, sizeof(*sapi_globals));
                     61:        zend_hash_init_ex(&sapi_globals->known_post_content_types, 5, NULL, NULL, 1, 0);
                     62:        php_setup_sapi_content_types(TSRMLS_C);
                     63: }
                     64: 
                     65: static void sapi_globals_dtor(sapi_globals_struct *sapi_globals TSRMLS_DC)
                     66: {
                     67:        zend_hash_destroy(&sapi_globals->known_post_content_types);
                     68: }
                     69: 
                     70: /* True globals (no need for thread safety) */
                     71: SAPI_API sapi_module_struct sapi_module;
                     72: 
                     73: 
                     74: SAPI_API void sapi_startup(sapi_module_struct *sf)
                     75: {
                     76:        sf->ini_entries = NULL;
                     77:        sapi_module = *sf;
                     78: 
                     79: #ifdef ZTS
                     80:        ts_allocate_id(&sapi_globals_id, sizeof(sapi_globals_struct), (ts_allocate_ctor) sapi_globals_ctor, (ts_allocate_dtor) sapi_globals_dtor);
                     81: # ifdef PHP_WIN32
                     82:        _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
                     83: # endif
                     84: #else
                     85:        sapi_globals_ctor(&sapi_globals);
                     86: #endif
                     87: 
                     88:        virtual_cwd_startup(); /* Could use shutdown to free the main cwd but it would just slow it down for CGI */
                     89: 
                     90: #ifdef PHP_WIN32
                     91:        tsrm_win32_startup();
                     92: #endif
                     93: 
                     94:        reentrancy_startup();
                     95: }
                     96: 
                     97: SAPI_API void sapi_shutdown(void)
                     98: {
                     99: #ifdef ZTS
                    100:        ts_free_id(sapi_globals_id);
                    101: #else
                    102:        sapi_globals_dtor(&sapi_globals);
                    103: #endif
                    104: 
                    105:        reentrancy_shutdown();
                    106: 
                    107:        virtual_cwd_shutdown();
                    108: 
                    109: #ifdef PHP_WIN32
                    110:        tsrm_win32_shutdown();
                    111: #endif
                    112: }
                    113: 
                    114: 
                    115: SAPI_API void sapi_free_header(sapi_header_struct *sapi_header)
                    116: {
                    117:        efree(sapi_header->header);
                    118: }
                    119: 
                    120: 
                    121: SAPI_API void sapi_handle_post(void *arg TSRMLS_DC)
                    122: {
                    123:        if (SG(request_info).post_entry && SG(request_info).content_type_dup) {
                    124:                SG(request_info).post_entry->post_handler(SG(request_info).content_type_dup, arg TSRMLS_CC);
                    125:                if (SG(request_info).post_data) {
                    126:                        efree(SG(request_info).post_data);
                    127:                        SG(request_info).post_data = NULL;
                    128:                }
                    129:                efree(SG(request_info).content_type_dup);
                    130:                SG(request_info).content_type_dup = NULL;
                    131:        }
                    132: }
                    133: 
                    134: static void sapi_read_post_data(TSRMLS_D)
                    135: {
                    136:        sapi_post_entry *post_entry;
                    137:        uint content_type_length = strlen(SG(request_info).content_type);
                    138:        char *content_type = estrndup(SG(request_info).content_type, content_type_length);
                    139:        char *p;
                    140:        char oldchar=0;
                    141:        void (*post_reader_func)(TSRMLS_D) = NULL;
                    142: 
                    143: 
                    144:        /* dedicated implementation for increased performance:
                    145:         * - Make the content type lowercase
                    146:         * - Trim descriptive data, stay with the content-type only
                    147:         */
                    148:        for (p=content_type; p<content_type+content_type_length; p++) {
                    149:                switch (*p) {
                    150:                        case ';':
                    151:                        case ',':
                    152:                        case ' ':
                    153:                                content_type_length = p-content_type;
                    154:                                oldchar = *p;
                    155:                                *p = 0;
                    156:                                break;
                    157:                        default:
                    158:                                *p = tolower(*p);
                    159:                                break;
                    160:                }
                    161:        }
                    162: 
                    163:        /* now try to find an appropriate POST content handler */
                    164:        if (zend_hash_find(&SG(known_post_content_types), content_type,
                    165:                        content_type_length+1, (void **) &post_entry) == SUCCESS) {
                    166:                /* found one, register it for use */
                    167:                SG(request_info).post_entry = post_entry;
                    168:                post_reader_func = post_entry->post_reader;
                    169:        } else {
                    170:                /* fallback */
                    171:                SG(request_info).post_entry = NULL;
                    172:                if (!sapi_module.default_post_reader) {
                    173:                        /* no default reader ? */
                    174:                        SG(request_info).content_type_dup = NULL;
                    175:                        sapi_module.sapi_error(E_WARNING, "Unsupported content type:  '%s'", content_type);
                    176:                        return;
                    177:                }
                    178:        }
                    179:        if (oldchar) {
                    180:                *(p-1) = oldchar;
                    181:        }
                    182: 
                    183:        SG(request_info).content_type_dup = content_type;
                    184: 
                    185:        if(post_reader_func) {
                    186:                post_reader_func(TSRMLS_C);
                    187:        }
                    188: 
                    189:        if(sapi_module.default_post_reader) {
                    190:                sapi_module.default_post_reader(TSRMLS_C);
                    191:        }
                    192: }
                    193: 
                    194: 
                    195: SAPI_API SAPI_POST_READER_FUNC(sapi_read_standard_form_data)
                    196: {
                    197:        int read_bytes;
                    198:        int allocated_bytes=SAPI_POST_BLOCK_SIZE+1;
                    199: 
                    200:        if ((SG(post_max_size) > 0) && (SG(request_info).content_length > SG(post_max_size))) {
                    201:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "POST Content-Length of %ld bytes exceeds the limit of %ld bytes",
                    202:                                        SG(request_info).content_length, SG(post_max_size));
                    203:                return;
                    204:        }
                    205:        SG(request_info).post_data = emalloc(allocated_bytes);
                    206: 
                    207:        for (;;) {
                    208:                read_bytes = sapi_module.read_post(SG(request_info).post_data+SG(read_post_bytes), SAPI_POST_BLOCK_SIZE TSRMLS_CC);
                    209:                if (read_bytes<=0) {
                    210:                        break;
                    211:                }
                    212:                SG(read_post_bytes) += read_bytes;
                    213:                if ((SG(post_max_size) > 0) && (SG(read_post_bytes) > SG(post_max_size))) {
                    214:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Actual POST length does not match Content-Length, and exceeds %ld bytes", SG(post_max_size));
                    215:                        break;
                    216:                }
                    217:                if (read_bytes < SAPI_POST_BLOCK_SIZE) {
                    218:                        break;
                    219:                }
                    220:                if (SG(read_post_bytes)+SAPI_POST_BLOCK_SIZE >= allocated_bytes) {
                    221:                        allocated_bytes = SG(read_post_bytes)+SAPI_POST_BLOCK_SIZE+1;
                    222:                        SG(request_info).post_data = erealloc(SG(request_info).post_data, allocated_bytes);
                    223:                }
                    224:        }
                    225:        SG(request_info).post_data[SG(read_post_bytes)] = 0;  /* terminating NULL */
                    226:        SG(request_info).post_data_length = SG(read_post_bytes);
                    227: }
                    228: 
                    229: 
                    230: SAPI_API char *sapi_get_default_content_type(TSRMLS_D)
                    231: {
                    232:        char *mimetype, *charset, *content_type;
                    233: 
                    234:        mimetype = SG(default_mimetype) ? SG(default_mimetype) : SAPI_DEFAULT_MIMETYPE;
                    235:        charset = SG(default_charset) ? SG(default_charset) : SAPI_DEFAULT_CHARSET;
                    236: 
                    237:        if (strncasecmp(mimetype, "text/", 5) == 0 && *charset) {
                    238:                int len = strlen(mimetype) + sizeof("; charset=") + strlen(charset); /* sizeof() includes \0 */
                    239:                content_type = emalloc(len);
                    240:                snprintf(content_type, len, "%s; charset=%s", mimetype, charset);
                    241:        } else {
                    242:                content_type = estrdup(mimetype);
                    243:        }
                    244:        return content_type;
                    245: }
                    246: 
                    247: 
                    248: SAPI_API void sapi_get_default_content_type_header(sapi_header_struct *default_header TSRMLS_DC)
                    249: {
                    250:        char *default_content_type = sapi_get_default_content_type(TSRMLS_C);
                    251:        int default_content_type_len = strlen(default_content_type);
                    252: 
                    253:        default_header->header_len = (sizeof("Content-type: ")-1) + default_content_type_len;
                    254:        default_header->header = emalloc(default_header->header_len+1);
                    255:        memcpy(default_header->header, "Content-type: ", sizeof("Content-type: "));
                    256:        memcpy(default_header->header+sizeof("Content-type: ")-1, default_content_type, default_content_type_len);
                    257:        default_header->header[default_header->header_len] = 0;
                    258:        efree(default_content_type);
                    259: }
                    260: 
                    261: /*
                    262:  * Add charset on content-type header if the MIME type starts with
                    263:  * "text/", the default_charset directive is not empty and
                    264:  * there is not already a charset option in there.
                    265:  *
                    266:  * If "mimetype" is non-NULL, it should point to a pointer allocated
                    267:  * with emalloc().  If a charset is added, the string will be
                    268:  * re-allocated and the new length is returned.  If mimetype is
                    269:  * unchanged, 0 is returned.
                    270:  *
                    271:  */
                    272: SAPI_API size_t sapi_apply_default_charset(char **mimetype, size_t len TSRMLS_DC)
                    273: {
                    274:        char *charset, *newtype;
                    275:        size_t newlen;
                    276:        charset = SG(default_charset) ? SG(default_charset) : SAPI_DEFAULT_CHARSET;
                    277: 
                    278:        if (*mimetype != NULL) {
                    279:                if (*charset && strncmp(*mimetype, "text/", 5) == 0 && strstr(*mimetype, "charset=") == NULL) {
                    280:                        newlen = len + (sizeof(";charset=")-1) + strlen(charset);
                    281:                        newtype = emalloc(newlen + 1);
                    282:                        PHP_STRLCPY(newtype, *mimetype, newlen + 1, len);
                    283:                        strlcat(newtype, ";charset=", newlen + 1);
                    284:                        strlcat(newtype, charset, newlen + 1);
                    285:                        efree(*mimetype);
                    286:                        *mimetype = newtype;
                    287:                        return newlen;
                    288:                }
                    289:        }
                    290:        return 0;
                    291: }
                    292: 
                    293: SAPI_API void sapi_activate_headers_only(TSRMLS_D)
                    294: {
                    295:        if (SG(request_info).headers_read == 1)
                    296:                return;
                    297:        SG(request_info).headers_read = 1;
                    298:        zend_llist_init(&SG(sapi_headers).headers, sizeof(sapi_header_struct), 
                    299:                        (void (*)(void *)) sapi_free_header, 0);
                    300:        SG(sapi_headers).send_default_content_type = 1;
                    301: 
                    302:        /* SG(sapi_headers).http_response_code = 200; */ 
                    303:        SG(sapi_headers).http_status_line = NULL;
                    304:        SG(sapi_headers).mimetype = NULL;
                    305:        SG(read_post_bytes) = 0;
                    306:        SG(request_info).post_data = NULL;
                    307:        SG(request_info).raw_post_data = NULL;
                    308:        SG(request_info).current_user = NULL;
                    309:        SG(request_info).current_user_length = 0;
                    310:        SG(request_info).no_headers = 0;
                    311:        SG(request_info).post_entry = NULL;
                    312:        SG(global_request_time) = 0;
                    313: 
                    314:        /*
                    315:         * It's possible to override this general case in the activate() callback, 
                    316:         * if necessary.
                    317:         */
                    318:        if (SG(request_info).request_method && !strcmp(SG(request_info).request_method, "HEAD")) {
                    319:                SG(request_info).headers_only = 1;
                    320:        } else {
                    321:                SG(request_info).headers_only = 0;
                    322:        }
                    323:        if (SG(server_context)) {
                    324:                SG(request_info).cookie_data = sapi_module.read_cookies(TSRMLS_C);
                    325:                if (sapi_module.activate) {
                    326:                        sapi_module.activate(TSRMLS_C);
                    327:                }
                    328:        }
                    329:        if (sapi_module.input_filter_init ) {
                    330:                sapi_module.input_filter_init(TSRMLS_C);
                    331:        }
                    332: }
                    333: 
                    334: /*
                    335:  * Called from php_request_startup() for every request.
                    336:  */
                    337: 
                    338: SAPI_API void sapi_activate(TSRMLS_D)
                    339: {
                    340:        zend_llist_init(&SG(sapi_headers).headers, sizeof(sapi_header_struct), (void (*)(void *)) sapi_free_header, 0);
                    341:        SG(sapi_headers).send_default_content_type = 1;
                    342: 
                    343:        /*
                    344:        SG(sapi_headers).http_response_code = 200;
                    345:        */
                    346:        SG(sapi_headers).http_status_line = NULL;
                    347:        SG(sapi_headers).mimetype = NULL;
                    348:        SG(headers_sent) = 0;
                    349:        SG(read_post_bytes) = 0;
                    350:        SG(request_info).post_data = NULL;
                    351:        SG(request_info).raw_post_data = NULL;
                    352:        SG(request_info).current_user = NULL;
                    353:        SG(request_info).current_user_length = 0;
                    354:        SG(request_info).no_headers = 0;
                    355:        SG(request_info).post_entry = NULL;
                    356:        SG(request_info).proto_num = 1000; /* Default to HTTP 1.0 */
                    357:        SG(global_request_time) = 0;
                    358: 
                    359:        /* It's possible to override this general case in the activate() callback, if
                    360:         * necessary.
                    361:         */
                    362:        if (SG(request_info).request_method && !strcmp(SG(request_info).request_method, "HEAD")) {
                    363:                SG(request_info).headers_only = 1;
                    364:        } else {
                    365:                SG(request_info).headers_only = 0;
                    366:        }
                    367:        SG(rfc1867_uploaded_files) = NULL;
                    368: 
                    369:        /* handle request mehtod */
                    370:        if (SG(server_context)) {
                    371:                if ( SG(request_info).request_method) {
                    372:                        if(!strcmp(SG(request_info).request_method, "POST")
                    373:                           && (SG(request_info).content_type)) {
                    374:                                /* HTTP POST -> may contain form data to be read into variables
                    375:                                   depending on content type given
                    376:                                */
                    377:                                sapi_read_post_data(TSRMLS_C);
                    378:                        } else {
                    379:                                /* any other method with content payload will fill 
                    380:                                   $HTTP_RAW_POST_DATA if enabled by always_populate_raw_post_data 
                    381:                                   it is up to the webserver to decide whether to allow a method or not
                    382:                                */
                    383:                                SG(request_info).content_type_dup = NULL;
                    384:                                if(sapi_module.default_post_reader) {
                    385:                                        sapi_module.default_post_reader(TSRMLS_C);
                    386:                                }
                    387:                        }
                    388:                } else {
                    389:                        SG(request_info).content_type_dup = NULL;
                    390:                }
                    391: 
                    392:                /* Cookies */
                    393:                SG(request_info).cookie_data = sapi_module.read_cookies(TSRMLS_C);
                    394:                if (sapi_module.activate) {
                    395:                        sapi_module.activate(TSRMLS_C);
                    396:                }
                    397:        }
                    398:        if (sapi_module.input_filter_init ) {
                    399:                sapi_module.input_filter_init(TSRMLS_C);
                    400:        }
                    401: }
                    402: 
                    403: 
                    404: static void sapi_send_headers_free(TSRMLS_D)
                    405: {
                    406:        if (SG(sapi_headers).http_status_line) {
                    407:                efree(SG(sapi_headers).http_status_line);
                    408:                SG(sapi_headers).http_status_line = NULL;
                    409:        }
                    410: }
                    411:        
                    412: SAPI_API void sapi_deactivate(TSRMLS_D)
                    413: {
                    414:        zend_llist_destroy(&SG(sapi_headers).headers);
                    415:        if (SG(request_info).post_data) {
                    416:                efree(SG(request_info).post_data);
                    417:        }  else         if (SG(server_context)) {
                    418:                if(sapi_module.read_post) { 
                    419:                        /* make sure we've consumed all request input data */
                    420:                        char dummy[SAPI_POST_BLOCK_SIZE];
                    421:                        int read_bytes;
                    422: 
                    423:                        while((read_bytes = sapi_module.read_post(dummy, sizeof(dummy)-1 TSRMLS_CC)) > 0) {
                    424:                                SG(read_post_bytes) += read_bytes;
                    425:                        }
                    426:                }
                    427:        }
                    428:        if (SG(request_info).raw_post_data) {
                    429:                efree(SG(request_info).raw_post_data);
                    430:        } 
                    431:        if (SG(request_info).auth_user) {
                    432:                efree(SG(request_info).auth_user);
                    433:        }
                    434:        if (SG(request_info).auth_password) {
                    435:                efree(SG(request_info).auth_password);
                    436:        }
                    437:        if (SG(request_info).auth_digest) {
                    438:                efree(SG(request_info).auth_digest);
                    439:        }
                    440:        if (SG(request_info).content_type_dup) {
                    441:                efree(SG(request_info).content_type_dup);
                    442:        }
                    443:        if (SG(request_info).current_user) {
                    444:                efree(SG(request_info).current_user);
                    445:        }
                    446:        if (sapi_module.deactivate) {
                    447:                sapi_module.deactivate(TSRMLS_C);
                    448:        }
                    449:        if (SG(rfc1867_uploaded_files)) {
                    450:                destroy_uploaded_files_hash(TSRMLS_C);
                    451:        }
                    452:        if (SG(sapi_headers).mimetype) {
                    453:                efree(SG(sapi_headers).mimetype);
                    454:                SG(sapi_headers).mimetype = NULL;
                    455:        }
                    456:        sapi_send_headers_free(TSRMLS_C);
                    457:        SG(sapi_started) = 0;
                    458:        SG(headers_sent) = 0;
                    459:        SG(request_info).headers_read = 0;
                    460:        SG(global_request_time) = 0;
                    461: }
                    462: 
                    463: 
                    464: SAPI_API void sapi_initialize_empty_request(TSRMLS_D)
                    465: {
                    466:        SG(server_context) = NULL;
                    467:        SG(request_info).request_method = NULL;
                    468:        SG(request_info).auth_digest = SG(request_info).auth_user = SG(request_info).auth_password = NULL;
                    469:        SG(request_info).content_type_dup = NULL;
                    470: }
                    471: 
                    472: 
                    473: static int sapi_extract_response_code(const char *header_line)
                    474: {
                    475:        int code = 200;
                    476:        const char *ptr;
                    477: 
                    478:        for (ptr = header_line; *ptr; ptr++) {
                    479:                if (*ptr == ' ' && *(ptr + 1) != ' ') {
                    480:                        code = atoi(ptr + 1);
                    481:                        break;
                    482:                }
                    483:        }
                    484:        
                    485:        return code;
                    486: }
                    487: 
                    488: 
                    489: static void sapi_update_response_code(int ncode TSRMLS_DC)
                    490: {
                    491:        /* if the status code did not change, we do not want
                    492:           to change the status line, and no need to change the code */
                    493:        if (SG(sapi_headers).http_response_code == ncode) {
                    494:                return;
                    495:        }
                    496: 
                    497:        if (SG(sapi_headers).http_status_line) {
                    498:                efree(SG(sapi_headers).http_status_line);
                    499:                SG(sapi_headers).http_status_line = NULL;
                    500:        }
                    501:        SG(sapi_headers).http_response_code = ncode;
                    502: }
                    503: 
                    504: static int sapi_find_matching_header(void *element1, void *element2)
                    505: {
                    506:        int len = strlen((char*)element2);
                    507:        return strncasecmp(((sapi_header_struct*)element1)->header, (char*)element2, len) == 0 && ((sapi_header_struct*)element1)->header[len] == ':';
                    508: }
                    509: 
                    510: SAPI_API int sapi_add_header_ex(char *header_line, uint header_line_len, zend_bool duplicate, zend_bool replace TSRMLS_DC)
                    511: {
                    512:        sapi_header_line ctr = {0};
                    513:        int r;
                    514:        
                    515:        ctr.line = header_line;
                    516:        ctr.line_len = header_line_len;
                    517: 
                    518:        r = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD,
                    519:                        &ctr TSRMLS_CC);
                    520: 
                    521:        if (!duplicate)
                    522:                efree(header_line);
                    523: 
                    524:        return r;
                    525: }
                    526: 
                    527: SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC)
                    528: {
                    529:        int retval;
                    530:        sapi_header_struct sapi_header;
                    531:        char *colon_offset;
                    532:        long myuid = 0L;
                    533:        char *header_line;
                    534:        uint header_line_len;
                    535:        int http_response_code;
                    536:        
                    537:        if (SG(headers_sent) && !SG(request_info).no_headers) {
                    538:                char *output_start_filename = php_get_output_start_filename(TSRMLS_C);
                    539:                int output_start_lineno = php_get_output_start_lineno(TSRMLS_C);
                    540: 
                    541:                if (output_start_filename) {
                    542:                        sapi_module.sapi_error(E_WARNING, "Cannot modify header information - headers already sent by (output started at %s:%d)",
                    543:                                output_start_filename, output_start_lineno);
                    544:                } else {
                    545:                        sapi_module.sapi_error(E_WARNING, "Cannot modify header information - headers already sent");
                    546:                }
                    547:                return FAILURE;
                    548:        }
                    549: 
                    550:        switch (op) {
                    551:                case SAPI_HEADER_SET_STATUS:
                    552:                        sapi_update_response_code((int)(zend_intptr_t) arg TSRMLS_CC);
                    553:                        return SUCCESS;
                    554: 
                    555:                case SAPI_HEADER_ADD:
                    556:                case SAPI_HEADER_REPLACE:
                    557:                case SAPI_HEADER_DELETE: {
                    558:                                sapi_header_line *p = arg;
                    559: 
                    560:                                if (!p->line || !p->line_len) {
                    561:                                        return FAILURE;
                    562:                                }
                    563:                                header_line = p->line;
                    564:                                header_line_len = p->line_len;
                    565:                                http_response_code = p->response_code;
                    566:                                break;
                    567:                        }
                    568: 
                    569:                case SAPI_HEADER_DELETE_ALL:
                    570:                        if (sapi_module.header_handler) {
                    571:                                sapi_module.header_handler(&sapi_header, op, &SG(sapi_headers) TSRMLS_CC);
                    572:                        }
                    573:                        zend_llist_clean(&SG(sapi_headers).headers);
                    574:                        return SUCCESS;
                    575: 
                    576:                default:
                    577:                        return FAILURE;
                    578:        }
                    579: 
                    580:        header_line = estrndup(header_line, header_line_len);
                    581: 
                    582:        /* cut of trailing spaces, linefeeds and carriage-returns */
                    583:        while(header_line_len && isspace(header_line[header_line_len-1])) 
                    584:                  header_line[--header_line_len]='\0';
                    585:        
                    586:        if (op == SAPI_HEADER_DELETE) {
                    587:                if (strchr(header_line, ':')) {
                    588:                        efree(header_line);
                    589:                        sapi_module.sapi_error(E_WARNING, "Header to delete may not contain colon.");
                    590:                        return FAILURE;
                    591:                }
                    592:        } else {
                    593:                /* new line safety check */
                    594:                char *s = header_line, *e = header_line + header_line_len, *p;
                    595:                while (s < e && (p = memchr(s, '\n', (e - s)))) {
                    596:                        if (*(p + 1) == ' ' || *(p + 1) == '\t') {
                    597:                                s = p + 1;
                    598:                                continue;
                    599:                        }
                    600:                        efree(header_line);
                    601:                        sapi_module.sapi_error(E_WARNING, "Header may not contain more than a single header, new line detected.");
                    602:                        return FAILURE;
                    603:                }
                    604:        }
                    605: 
                    606:        sapi_header.header = header_line;
                    607:        sapi_header.header_len = header_line_len;
                    608: 
                    609:        if (op == SAPI_HEADER_DELETE) {
                    610:                if (sapi_module.header_handler) {
                    611:                        sapi_module.header_handler(&sapi_header, op, &SG(sapi_headers) TSRMLS_CC);
                    612:                }
                    613:                zend_llist_del_element(&SG(sapi_headers).headers, sapi_header.header, (int(*)(void*, void*))sapi_find_matching_header);
                    614:                sapi_free_header(&sapi_header);
                    615:                return SUCCESS;
                    616:        }
                    617: 
                    618:        /* Check the header for a few cases that we have special support for in SAPI */
                    619:        if (header_line_len>=5 
                    620:                && !strncasecmp(header_line, "HTTP/", 5)) {
                    621:                /* filter out the response code */
                    622:                sapi_update_response_code(sapi_extract_response_code(header_line) TSRMLS_CC);
                    623:                /* sapi_update_response_code doesn't free the status line if the code didn't change */
                    624:                if (SG(sapi_headers).http_status_line) {
                    625:                        efree(SG(sapi_headers).http_status_line);
                    626:                }
                    627:                SG(sapi_headers).http_status_line = header_line;
                    628:                return SUCCESS;
                    629:        } else {
                    630:                colon_offset = strchr(header_line, ':');
                    631:                if (colon_offset) {
                    632:                        *colon_offset = 0;
                    633:                        if (!STRCASECMP(header_line, "Content-Type")) {
                    634:                                char *ptr = colon_offset+1, *mimetype = NULL, *newheader;
                    635:                                size_t len = header_line_len - (ptr - header_line), newlen;
                    636:                                while (*ptr == ' ') {
                    637:                                        ptr++;
                    638:                                        len--;
                    639:                                }
                    640: 
                    641:                                /* Disable possible output compression for images */
                    642:                                if (!strncmp(ptr, "image/", sizeof("image/")-1)) {
                    643:                                        zend_alter_ini_entry("zlib.output_compression", sizeof("zlib.output_compression"), "0", sizeof("0") - 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
                    644:                                }
                    645: 
                    646:                                mimetype = estrdup(ptr);
                    647:                                newlen = sapi_apply_default_charset(&mimetype, len TSRMLS_CC);
                    648:                                if (!SG(sapi_headers).mimetype){
                    649:                                        SG(sapi_headers).mimetype = estrdup(mimetype);
                    650:                                }
                    651: 
                    652:                                if (newlen != 0) {
                    653:                                        newlen += sizeof("Content-type: ");
                    654:                                        newheader = emalloc(newlen);
                    655:                                        PHP_STRLCPY(newheader, "Content-type: ", newlen, sizeof("Content-type: ")-1);
                    656:                                        strlcat(newheader, mimetype, newlen);
                    657:                                        sapi_header.header = newheader;
                    658:                                        sapi_header.header_len = newlen - 1;
                    659:                                        efree(header_line);
                    660:                                }
                    661:                                efree(mimetype);
                    662:                                SG(sapi_headers).send_default_content_type = 0;
                    663:                        } else if (!STRCASECMP(header_line, "Location")) {
                    664:                                if ((SG(sapi_headers).http_response_code < 300 ||
                    665:                                        SG(sapi_headers).http_response_code > 307) &&
                    666:                                        SG(sapi_headers).http_response_code != 201) {
                    667:                                        /* Return a Found Redirect if one is not already specified */
                    668:                                        if (http_response_code) { /* user specified redirect code */
                    669:                                                sapi_update_response_code(http_response_code TSRMLS_CC);
                    670:                                        } else if (SG(request_info).proto_num > 1000 && 
                    671:                                           SG(request_info).request_method && 
                    672:                                           strcmp(SG(request_info).request_method, "HEAD") &&
                    673:                                           strcmp(SG(request_info).request_method, "GET")) {
                    674:                                                sapi_update_response_code(303 TSRMLS_CC);
                    675:                                        } else {
                    676:                                                sapi_update_response_code(302 TSRMLS_CC);
                    677:                                        }
                    678:                                }
                    679:                        } else if (!STRCASECMP(header_line, "WWW-Authenticate")) { /* HTTP Authentication */
                    680: 
                    681:                                sapi_update_response_code(401 TSRMLS_CC); /* authentication-required */
                    682: 
                    683:                                if(PG(safe_mode)) 
                    684: #if (HAVE_PCRE || HAVE_BUNDLED_PCRE) && !defined(COMPILE_DL_PCRE)
                    685:                                {
                    686:                                        zval *repl_temp;
                    687:                                        char *ptr = colon_offset+1, *result, *newheader;
                    688:                                        int ptr_len=0, result_len = 0, newlen = 0;
                    689: 
                    690:                                        /* skip white space */
                    691:                                        while (isspace(*ptr)) {
                    692:                                                ptr++;
                    693:                                        }
                    694: 
                    695:                                        myuid = php_getuid();
                    696: 
                    697:                                        ptr_len = strlen(ptr);
                    698:                                        MAKE_STD_ZVAL(repl_temp);
                    699:                                        Z_TYPE_P(repl_temp) = IS_STRING;
                    700:                                        Z_STRLEN_P(repl_temp) = spprintf(&Z_STRVAL_P(repl_temp), 0, "realm=\"\\1-%ld\"", myuid);
                    701:                                        /* Modify quoted realm value */
                    702:                                        result = php_pcre_replace("/realm=\"(.*?)\"/i", 16,
                    703:                                                                                         ptr, ptr_len,
                    704:                                                                                         repl_temp,
                    705:                                                                                         0, &result_len, -1, NULL TSRMLS_CC);
                    706:                                        if(result_len==ptr_len) {
                    707:                                                efree(result);
                    708:                                                efree(Z_STRVAL_P(repl_temp));
                    709:                                                Z_STRLEN_P(repl_temp) = spprintf(&Z_STRVAL_P(repl_temp), 0, "realm=\\1-%ld\\2", myuid);
                    710:                                                /* modify unquoted realm value */
                    711:                                                result = php_pcre_replace("/realm=([^\\s]+)(.*)/i", 21, 
                    712:                                                                                                ptr, ptr_len,
                    713:                                                                                                repl_temp,
                    714:                                                                                                0, &result_len, -1, NULL TSRMLS_CC);
                    715:                                                if(result_len==ptr_len) {
                    716:                                                        char *lower_temp = estrdup(ptr);        
                    717:                                                        char conv_temp[32];
                    718:                                                        int conv_len;
                    719: 
                    720:                                                        php_strtolower(lower_temp,strlen(lower_temp));
                    721:                                                        /* If there is no realm string at all, append one */
                    722:                                                        if(!strstr(lower_temp,"realm")) {
                    723:                                                                efree(result);
                    724:                                                                conv_len = slprintf(conv_temp, sizeof(conv_temp), " realm=\"%ld\"",myuid);
                    725:                                                                result = emalloc(ptr_len+conv_len+1);
                    726:                                                                result_len = ptr_len+conv_len;
                    727:                                                                memcpy(result, ptr, ptr_len);   
                    728:                                                                memcpy(result+ptr_len, conv_temp, conv_len);
                    729:                                                                *(result+ptr_len+conv_len) = '\0';
                    730:                                                        }
                    731:                                                        efree(lower_temp);
                    732:                                                }
                    733:                                        }
                    734:                                        newlen = spprintf(&newheader, 0, "WWW-Authenticate: %s", result);
                    735:                                        efree(header_line);
                    736:                                        sapi_header.header = newheader;
                    737:                                        sapi_header.header_len = newlen;
                    738:                                        efree(result);
                    739:                                        efree(Z_STRVAL_P(repl_temp));
                    740:                                        efree(repl_temp);
                    741:                                } 
                    742: #else
                    743:                                {
                    744:                                        myuid = php_getuid();
                    745:                                        efree(header_line);
                    746:                                        sapi_header.header_len = spprintf(&sapi_header.header, 0, "WWW-Authenticate: Basic realm=\"%ld\"", myuid);
                    747:                                }
                    748: #endif
                    749:                        }
                    750:                        if (sapi_header.header==header_line) {
                    751:                                *colon_offset = ':';
                    752:                        }
                    753:                }
                    754:        }
                    755:        if (http_response_code) {
                    756:                sapi_update_response_code(http_response_code TSRMLS_CC);
                    757:        }
                    758:        if (sapi_module.header_handler) {
                    759:                retval = sapi_module.header_handler(&sapi_header, op, &SG(sapi_headers) TSRMLS_CC);
                    760:        } else {
                    761:                retval = SAPI_HEADER_ADD;
                    762:        }
                    763:        if (retval & SAPI_HEADER_ADD) {
                    764:                /* in replace mode first remove the header if it already exists in the headers llist */
                    765:                if (op == SAPI_HEADER_REPLACE) {
                    766:                        colon_offset = strchr(sapi_header.header, ':');
                    767:                        if (colon_offset) {
                    768:                                char sav;
                    769:                                sav = *colon_offset;
                    770:                                *colon_offset = 0;
                    771:                                zend_llist_del_element(&SG(sapi_headers).headers, sapi_header.header, (int(*)(void*, void*))sapi_find_matching_header);
                    772:                                *colon_offset = sav;
                    773:                        }
                    774:                }
                    775: 
                    776:                zend_llist_add_element(&SG(sapi_headers).headers, (void *) &sapi_header);
                    777:        } else {
                    778:                sapi_free_header(&sapi_header);
                    779:        }
                    780:        return SUCCESS;
                    781: }
                    782: 
                    783: 
                    784: SAPI_API int sapi_send_headers(TSRMLS_D)
                    785: {
                    786:        int retval;
                    787:        int ret = FAILURE;
                    788: 
                    789:        if (SG(headers_sent) || SG(request_info).no_headers) {
                    790:                return SUCCESS;
                    791:        }
                    792: 
                    793:        /* Success-oriented.  We set headers_sent to 1 here to avoid an infinite loop
                    794:         * in case of an error situation.
                    795:         */
                    796:        if (SG(sapi_headers).send_default_content_type && sapi_module.send_headers) {
                    797:                sapi_header_struct default_header;
                    798:                sapi_get_default_content_type_header(&default_header TSRMLS_CC);
                    799:                sapi_add_header_ex(default_header.header, default_header.header_len, 0, 0 TSRMLS_CC);
                    800:        }
                    801: 
                    802:        SG(headers_sent) = 1;
                    803: 
                    804:        if (sapi_module.send_headers) {
                    805:                retval = sapi_module.send_headers(&SG(sapi_headers) TSRMLS_CC);
                    806:        } else {
                    807:                retval = SAPI_HEADER_DO_SEND;
                    808:        }
                    809: 
                    810:        switch (retval) {
                    811:                case SAPI_HEADER_SENT_SUCCESSFULLY:
                    812:                        ret = SUCCESS;
                    813:                        break;
                    814:                case SAPI_HEADER_DO_SEND: {
                    815:                                sapi_header_struct http_status_line;
                    816:                                char buf[255];
                    817: 
                    818:                                if (SG(sapi_headers).http_status_line) {
                    819:                                        http_status_line.header = SG(sapi_headers).http_status_line;
                    820:                                        http_status_line.header_len = strlen(SG(sapi_headers).http_status_line);
                    821:                                } else {
                    822:                                        http_status_line.header = buf;
                    823:                                        http_status_line.header_len = slprintf(buf, sizeof(buf), "HTTP/1.0 %d X", SG(sapi_headers).http_response_code);
                    824:                                }
                    825:                                sapi_module.send_header(&http_status_line, SG(server_context) TSRMLS_CC);
                    826:                        }
                    827:                        zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t) sapi_module.send_header, SG(server_context) TSRMLS_CC);
                    828:                        if(SG(sapi_headers).send_default_content_type) {
                    829:                                sapi_header_struct default_header;
                    830: 
                    831:                                sapi_get_default_content_type_header(&default_header TSRMLS_CC);
                    832:                                sapi_module.send_header(&default_header, SG(server_context) TSRMLS_CC);
                    833:                                sapi_free_header(&default_header);
                    834:                        }
                    835:                        sapi_module.send_header(NULL, SG(server_context) TSRMLS_CC);
                    836:                        ret = SUCCESS;
                    837:                        break;
                    838:                case SAPI_HEADER_SEND_FAILED:
                    839:                        SG(headers_sent) = 0;
                    840:                        ret = FAILURE;
                    841:                        break;
                    842:        }
                    843: 
                    844:        sapi_send_headers_free(TSRMLS_C);
                    845: 
                    846:        return ret;
                    847: }
                    848: 
                    849: 
                    850: SAPI_API int sapi_register_post_entries(sapi_post_entry *post_entries TSRMLS_DC)
                    851: {
                    852:        sapi_post_entry *p=post_entries;
                    853: 
                    854:        while (p->content_type) {
                    855:                if (sapi_register_post_entry(p TSRMLS_CC) == FAILURE) {
                    856:                        return FAILURE;
                    857:                }
                    858:                p++;
                    859:        }
                    860:        return SUCCESS;
                    861: }
                    862: 
                    863: 
                    864: SAPI_API int sapi_register_post_entry(sapi_post_entry *post_entry TSRMLS_DC)
                    865: {
                    866:        if (SG(sapi_started) && EG(in_execution)) {
                    867:                return FAILURE;
                    868:        }
                    869:        return zend_hash_add(&SG(known_post_content_types),
                    870:                        post_entry->content_type, post_entry->content_type_len+1,
                    871:                        (void *) post_entry, sizeof(sapi_post_entry), NULL);
                    872: }
                    873: 
                    874: SAPI_API void sapi_unregister_post_entry(sapi_post_entry *post_entry TSRMLS_DC)
                    875: {
                    876:        if (SG(sapi_started) && EG(in_execution)) {
                    877:                return;
                    878:        }
                    879:        zend_hash_del(&SG(known_post_content_types), post_entry->content_type,
                    880:                        post_entry->content_type_len+1);
                    881: }
                    882: 
                    883: 
                    884: SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(TSRMLS_D))
                    885: {
                    886:        TSRMLS_FETCH();
                    887:        if (SG(sapi_started) && EG(in_execution)) {
                    888:                return FAILURE;
                    889:        }
                    890:        sapi_module.default_post_reader = default_post_reader;
                    891:        return SUCCESS;
                    892: }
                    893: 
                    894: 
                    895: SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zval *destArray TSRMLS_DC))
                    896: {
                    897:        TSRMLS_FETCH();
                    898:        if (SG(sapi_started) && EG(in_execution)) {
                    899:                return FAILURE;
                    900:        }
                    901:        sapi_module.treat_data = treat_data;
                    902:        return SUCCESS;
                    903: }
                    904: 
                    905: SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC), unsigned int (*input_filter_init)(TSRMLS_D))
                    906: {
                    907:        TSRMLS_FETCH();
                    908:        if (SG(sapi_started) && EG(in_execution)) {
                    909:                return FAILURE;
                    910:        }
                    911:        sapi_module.input_filter = input_filter;
                    912:        sapi_module.input_filter_init = input_filter_init;
                    913:        return SUCCESS;
                    914: }
                    915: 
                    916: SAPI_API int sapi_flush(TSRMLS_D)
                    917: {
                    918:        if (sapi_module.flush) {
                    919:                sapi_module.flush(SG(server_context));
                    920:                return SUCCESS;
                    921:        } else {
                    922:                return FAILURE;
                    923:        }
                    924: }
                    925: 
                    926: SAPI_API struct stat *sapi_get_stat(TSRMLS_D)
                    927: {
                    928:        if (sapi_module.get_stat) {
                    929:                return sapi_module.get_stat(TSRMLS_C);
                    930:        } else {
                    931:                if (!SG(request_info).path_translated || (VCWD_STAT(SG(request_info).path_translated, &SG(global_stat)) == -1)) {
                    932:                        return NULL;
                    933:                }
                    934:                return &SG(global_stat);
                    935:        }
                    936: }
                    937: 
                    938: SAPI_API char *sapi_getenv(char *name, size_t name_len TSRMLS_DC)
                    939: {
                    940:        if (sapi_module.getenv) { 
                    941:                char *value, *tmp = sapi_module.getenv(name, name_len TSRMLS_CC);
                    942:                if (tmp) {
                    943:                        value = estrdup(tmp);
                    944:                } else {
                    945:                        return NULL;
                    946:                }
                    947:                sapi_module.input_filter(PARSE_ENV, name, &value, strlen(value), NULL TSRMLS_CC);
                    948:                return value;
                    949:        }
                    950:        return NULL;
                    951: }
                    952: 
                    953: SAPI_API int sapi_get_fd(int *fd TSRMLS_DC)
                    954: {
                    955:        if (sapi_module.get_fd) {
                    956:                return sapi_module.get_fd(fd TSRMLS_CC);
                    957:        } else {
                    958:                return FAILURE;
                    959:        }
                    960: }
                    961: 
                    962: SAPI_API int sapi_force_http_10(TSRMLS_D)
                    963: {
                    964:        if (sapi_module.force_http_10) {
                    965:                return sapi_module.force_http_10(TSRMLS_C);
                    966:        } else {
                    967:                return FAILURE;
                    968:        }
                    969: }
                    970: 
                    971: 
                    972: SAPI_API int sapi_get_target_uid(uid_t *obj TSRMLS_DC)
                    973: {
                    974:        if (sapi_module.get_target_uid) {
                    975:                return sapi_module.get_target_uid(obj TSRMLS_CC);
                    976:        } else {
                    977:                return FAILURE;
                    978:        }
                    979: }
                    980: 
                    981: SAPI_API int sapi_get_target_gid(gid_t *obj TSRMLS_DC)
                    982: {
                    983:        if (sapi_module.get_target_gid) {
                    984:                return sapi_module.get_target_gid(obj TSRMLS_CC);
                    985:        } else {
                    986:                return FAILURE;
                    987:        }
                    988: }
                    989: 
                    990: SAPI_API time_t sapi_get_request_time(TSRMLS_D)
                    991: {
                    992:        if(SG(global_request_time)) return SG(global_request_time);
                    993: 
                    994:        if (sapi_module.get_request_time && SG(server_context)) {
                    995:                SG(global_request_time) = sapi_module.get_request_time(TSRMLS_C);
                    996:        } else {
                    997:                SG(global_request_time) = time(0);
                    998:        }
                    999:        return SG(global_request_time);
                   1000: }
                   1001: 
                   1002: SAPI_API void sapi_terminate_process(TSRMLS_D) {
                   1003:        if (sapi_module.terminate_process) {
                   1004:                sapi_module.terminate_process(TSRMLS_C);
                   1005:        }
                   1006: }
                   1007: 
                   1008: /*
                   1009:  * Local variables:
                   1010:  * tab-width: 4
                   1011:  * c-basic-offset: 4
                   1012:  * End:
                   1013:  * vim600: sw=4 ts=4 fdm=marker
                   1014:  * vim<600: sw=4 ts=4
                   1015:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>