Annotation of embedaddon/php/sapi/cgi/cgi_main.c, revision 1.1.1.2

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:    | Authors: Rasmus Lerdorf <rasmus@lerdorf.on.ca>                       |
                     16:    |          Stig Bakken <ssb@php.net>                                   |
                     17:    |          Zeev Suraski <zeev@zend.com>                                |
                     18:    | FastCGI: Ben Mansell <php@slimyhorror.com>                           |
                     19:    |          Shane Caraveo <shane@caraveo.com>                           |
                     20:    |          Dmitry Stogov <dmitry@zend.com>                             |
                     21:    +----------------------------------------------------------------------+
                     22: */
                     23: 
1.1.1.2 ! misho      24: /* $Id$ */
1.1       misho      25: 
                     26: #include "php.h"
                     27: #include "php_globals.h"
                     28: #include "php_variables.h"
                     29: #include "zend_modules.h"
                     30: 
                     31: #include "SAPI.h"
                     32: 
                     33: #include <stdio.h>
                     34: #include "php.h"
                     35: 
                     36: #ifdef PHP_WIN32
                     37: # include "win32/time.h"
                     38: # include "win32/signal.h"
                     39: # include <process.h>
                     40: #endif
                     41: 
                     42: #if HAVE_SYS_TIME_H
                     43: # include <sys/time.h>
                     44: #endif
                     45: 
                     46: #if HAVE_UNISTD_H
                     47: # include <unistd.h>
                     48: #endif
                     49: 
                     50: #if HAVE_SIGNAL_H
                     51: # include <signal.h>
                     52: #endif
                     53: 
                     54: #if HAVE_SETLOCALE
                     55: # include <locale.h>
                     56: #endif
                     57: 
                     58: #if HAVE_SYS_TYPES_H
                     59: # include <sys/types.h>
                     60: #endif
                     61: 
                     62: #if HAVE_SYS_WAIT_H
                     63: # include <sys/wait.h>
                     64: #endif
                     65: 
                     66: #include "zend.h"
                     67: #include "zend_extensions.h"
                     68: #include "php_ini.h"
                     69: #include "php_globals.h"
                     70: #include "php_main.h"
                     71: #include "fopen_wrappers.h"
                     72: #include "ext/standard/php_standard.h"
1.1.1.2 ! misho      73: #include "ext/standard/url.h"
1.1       misho      74: 
                     75: #ifdef PHP_WIN32
                     76: # include <io.h>
                     77: # include <fcntl.h>
                     78: # include "win32/php_registry.h"
                     79: #endif
                     80: 
                     81: #ifdef __riscos__
                     82: # include <unixlib/local.h>
                     83: int __riscosify_control = __RISCOSIFY_STRICT_UNIX_SPECS;
                     84: #endif
                     85: 
                     86: #include "zend_compile.h"
                     87: #include "zend_execute.h"
                     88: #include "zend_highlight.h"
                     89: #include "zend_indent.h"
                     90: 
                     91: #include "php_getopt.h"
                     92: 
                     93: #include "fastcgi.h"
                     94: 
                     95: #ifndef PHP_WIN32
                     96: /* XXX this will need to change later when threaded fastcgi is implemented.  shane */
                     97: struct sigaction act, old_term, old_quit, old_int;
                     98: #endif
                     99: 
                    100: static void (*php_php_import_environment_variables)(zval *array_ptr TSRMLS_DC);
                    101: 
                    102: #ifndef PHP_WIN32
                    103: /* these globals used for forking children on unix systems */
                    104: /**
                    105:  * Number of child processes that will get created to service requests
                    106:  */
                    107: static int children = 0;
                    108: 
1.1.1.2 ! misho     109: 
1.1       misho     110: /**
                    111:  * Set to non-zero if we are the parent process
                    112:  */
                    113: static int parent = 1;
                    114: 
                    115: /* Did parent received exit signals SIG_TERM/SIG_INT/SIG_QUIT */
                    116: static int exit_signal = 0;
                    117: 
                    118: /* Is Parent waiting for children to exit */
                    119: static int parent_waiting = 0;
                    120: 
                    121: /**
                    122:  * Process group
                    123:  */
                    124: static pid_t pgroup;
                    125: #endif
                    126: 
                    127: #define PHP_MODE_STANDARD      1
                    128: #define PHP_MODE_HIGHLIGHT     2
                    129: #define PHP_MODE_INDENT                3
                    130: #define PHP_MODE_LINT          4
                    131: #define PHP_MODE_STRIP         5
                    132: 
                    133: static char *php_optarg = NULL;
                    134: static int php_optind = 1;
                    135: static zend_module_entry cgi_module_entry;
                    136: 
                    137: static const opt_struct OPTIONS[] = {
                    138:        {'a', 0, "interactive"},
                    139:        {'b', 1, "bindpath"},
                    140:        {'C', 0, "no-chdir"},
                    141:        {'c', 1, "php-ini"},
                    142:        {'d', 1, "define"},
                    143:        {'e', 0, "profile-info"},
                    144:        {'f', 1, "file"},
                    145:        {'h', 0, "help"},
                    146:        {'i', 0, "info"},
                    147:        {'l', 0, "syntax-check"},
                    148:        {'m', 0, "modules"},
                    149:        {'n', 0, "no-php-ini"},
                    150:        {'q', 0, "no-header"},
                    151:        {'s', 0, "syntax-highlight"},
                    152:        {'s', 0, "syntax-highlighting"},
                    153:        {'w', 0, "strip"},
                    154:        {'?', 0, "usage"},/* help alias (both '?' and 'usage') */
                    155:        {'v', 0, "version"},
                    156:        {'z', 1, "zend-extension"},
                    157:        {'T', 1, "timing"},
                    158:        {'-', 0, NULL} /* end of args */
                    159: };
                    160: 
                    161: typedef struct _php_cgi_globals_struct {
                    162:        zend_bool rfc2616_headers;
                    163:        zend_bool nph;
                    164:        zend_bool check_shebang_line;
                    165:        zend_bool fix_pathinfo;
                    166:        zend_bool force_redirect;
                    167:        zend_bool discard_path;
                    168:        zend_bool fcgi_logging;
                    169:        char *redirect_status_env;
                    170: #ifdef PHP_WIN32
                    171:        zend_bool impersonate;
                    172: #endif
                    173:        HashTable user_config_cache;
                    174: } php_cgi_globals_struct;
                    175: 
                    176: /* {{{ user_config_cache
                    177:  *
                    178:  * Key for each cache entry is dirname(PATH_TRANSLATED).
                    179:  *
                    180:  * NOTE: Each cache entry config_hash contains the combination from all user ini files found in
                    181:  *       the path starting from doc_root throught to dirname(PATH_TRANSLATED).  There is no point
                    182:  *       storing per-file entries as it would not be possible to detect added / deleted entries
                    183:  *       between separate files.
                    184:  */
                    185: typedef struct _user_config_cache_entry {
                    186:        time_t expires;
                    187:        HashTable *user_config;
                    188: } user_config_cache_entry;
                    189: 
                    190: static void user_config_cache_entry_dtor(user_config_cache_entry *entry)
                    191: {
                    192:        zend_hash_destroy(entry->user_config);
                    193:        free(entry->user_config);
                    194: }
                    195: /* }}} */
                    196: 
                    197: #ifdef ZTS
                    198: static int php_cgi_globals_id;
                    199: #define CGIG(v) TSRMG(php_cgi_globals_id, php_cgi_globals_struct *, v)
                    200: #else
                    201: static php_cgi_globals_struct php_cgi_globals;
                    202: #define CGIG(v) (php_cgi_globals.v)
                    203: #endif
                    204: 
                    205: #ifdef PHP_WIN32
                    206: #define TRANSLATE_SLASHES(path) \
                    207:        { \
                    208:                char *tmp = path; \
                    209:                while (*tmp) { \
                    210:                        if (*tmp == '\\') *tmp = '/'; \
                    211:                        tmp++; \
                    212:                } \
                    213:        }
                    214: #else
                    215: #define TRANSLATE_SLASHES(path)
                    216: #endif
                    217: 
                    218: static int print_module_info(zend_module_entry *module, void *arg TSRMLS_DC)
                    219: {
                    220:        php_printf("%s\n", module->name);
                    221:        return 0;
                    222: }
                    223: 
                    224: static int module_name_cmp(const void *a, const void *b TSRMLS_DC)
                    225: {
                    226:        Bucket *f = *((Bucket **) a);
                    227:        Bucket *s = *((Bucket **) b);
                    228: 
                    229:        return strcasecmp(      ((zend_module_entry *)f->pData)->name,
                    230:                                                ((zend_module_entry *)s->pData)->name);
                    231: }
                    232: 
                    233: static void print_modules(TSRMLS_D)
                    234: {
                    235:        HashTable sorted_registry;
                    236:        zend_module_entry tmp;
                    237: 
                    238:        zend_hash_init(&sorted_registry, 50, NULL, NULL, 1);
                    239:        zend_hash_copy(&sorted_registry, &module_registry, NULL, &tmp, sizeof(zend_module_entry));
                    240:        zend_hash_sort(&sorted_registry, zend_qsort, module_name_cmp, 0 TSRMLS_CC);
                    241:        zend_hash_apply_with_argument(&sorted_registry, (apply_func_arg_t) print_module_info, NULL TSRMLS_CC);
                    242:        zend_hash_destroy(&sorted_registry);
                    243: }
                    244: 
                    245: static int print_extension_info(zend_extension *ext, void *arg TSRMLS_DC)
                    246: {
                    247:        php_printf("%s\n", ext->name);
                    248:        return 0;
                    249: }
                    250: 
                    251: static int extension_name_cmp(const zend_llist_element **f, const zend_llist_element **s TSRMLS_DC)
                    252: {
                    253:        return strcmp(  ((zend_extension *)(*f)->data)->name,
                    254:                                        ((zend_extension *)(*s)->data)->name);
                    255: }
                    256: 
                    257: static void print_extensions(TSRMLS_D)
                    258: {
                    259:        zend_llist sorted_exts;
                    260: 
                    261:        zend_llist_copy(&sorted_exts, &zend_extensions);
                    262:        sorted_exts.dtor = NULL;
                    263:        zend_llist_sort(&sorted_exts, extension_name_cmp TSRMLS_CC);
                    264:        zend_llist_apply_with_argument(&sorted_exts, (llist_apply_with_arg_func_t) print_extension_info, NULL TSRMLS_CC);
                    265:        zend_llist_destroy(&sorted_exts);
                    266: }
                    267: 
                    268: #ifndef STDOUT_FILENO
                    269: #define STDOUT_FILENO 1
                    270: #endif
                    271: 
1.1.1.2 ! misho     272: static inline size_t sapi_cgi_single_write(const char *str, uint str_length TSRMLS_DC)
1.1       misho     273: {
                    274: #ifdef PHP_WRITE_STDOUT
                    275:        long ret;
                    276: 
                    277:        ret = write(STDOUT_FILENO, str, str_length);
                    278:        if (ret <= 0) return 0;
                    279:        return ret;
                    280: #else
1.1.1.2 ! misho     281:        size_t ret;
        !           282: 
1.1       misho     283:        ret = fwrite(str, 1, MIN(str_length, 16384), stdout);
                    284:        return ret;
                    285: #endif
                    286: }
                    287: 
1.1.1.2 ! misho     288: static int sapi_cgi_ub_write(const char *str, uint str_length TSRMLS_DC)
1.1       misho     289: {
                    290:        const char *ptr = str;
                    291:        uint remaining = str_length;
                    292:        size_t ret;
                    293: 
                    294:        while (remaining > 0) {
1.1.1.2 ! misho     295:                ret = sapi_cgi_single_write(ptr, remaining TSRMLS_CC);
1.1       misho     296:                if (!ret) {
                    297:                        php_handle_aborted_connection();
                    298:                        return str_length - remaining;
                    299:                }
                    300:                ptr += ret;
                    301:                remaining -= ret;
                    302:        }
                    303: 
                    304:        return str_length;
                    305: }
                    306: 
1.1.1.2 ! misho     307: static int sapi_fcgi_ub_write(const char *str, uint str_length TSRMLS_DC)
        !           308: {
        !           309:        const char *ptr = str;
        !           310:        uint remaining = str_length;
        !           311:        fcgi_request *request = (fcgi_request*) SG(server_context);
        !           312: 
        !           313:        while (remaining > 0) {
        !           314:                long ret = fcgi_write(request, FCGI_STDOUT, ptr, remaining);
        !           315: 
        !           316:                if (ret <= 0) {
        !           317:                        php_handle_aborted_connection();
        !           318:                        return str_length - remaining;
        !           319:                }
        !           320:                ptr += ret;
        !           321:                remaining -= ret;
        !           322:        }
1.1       misho     323: 
1.1.1.2 ! misho     324:        return str_length;
        !           325: }
        !           326: 
        !           327: static void sapi_cgi_flush(void *server_context)
1.1       misho     328: {
1.1.1.2 ! misho     329:        if (fflush(stdout) == EOF) {
        !           330:                php_handle_aborted_connection();
        !           331:        }
        !           332: }
        !           333: 
        !           334: static void sapi_fcgi_flush(void *server_context)
        !           335: {
        !           336:        fcgi_request *request = (fcgi_request*) server_context;
        !           337: 
        !           338:        if (
1.1       misho     339: #ifndef PHP_WIN32
                    340:                !parent &&
                    341: #endif
                    342:                request && !fcgi_flush(request, 0)) {
1.1.1.2 ! misho     343: 
1.1       misho     344:                php_handle_aborted_connection();
                    345:        }
                    346: }
                    347: 
                    348: #define SAPI_CGI_MAX_HEADER_LENGTH 1024
                    349: 
                    350: typedef struct _http_error {
                    351:   int code;
                    352:   const char* msg;
                    353: } http_error;
                    354: 
                    355: static const http_error http_error_codes[] = {
                    356:        {100, "Continue"},
                    357:        {101, "Switching Protocols"},
                    358:        {200, "OK"},
                    359:        {201, "Created"},
                    360:        {202, "Accepted"},
                    361:        {203, "Non-Authoritative Information"},
                    362:        {204, "No Content"},
                    363:        {205, "Reset Content"},
                    364:        {206, "Partial Content"},
                    365:        {300, "Multiple Choices"},
                    366:        {301, "Moved Permanently"},
                    367:        {302, "Moved Temporarily"},
                    368:        {303, "See Other"},
                    369:        {304, "Not Modified"},
                    370:        {305, "Use Proxy"},
                    371:        {400, "Bad Request"},
                    372:        {401, "Unauthorized"},
                    373:        {402, "Payment Required"},
                    374:        {403, "Forbidden"},
                    375:        {404, "Not Found"},
                    376:        {405, "Method Not Allowed"},
                    377:        {406, "Not Acceptable"},
                    378:        {407, "Proxy Authentication Required"},
                    379:        {408, "Request Time-out"},
                    380:        {409, "Conflict"},
                    381:        {410, "Gone"},
                    382:        {411, "Length Required"},
                    383:        {412, "Precondition Failed"},
                    384:        {413, "Request Entity Too Large"},
                    385:        {414, "Request-URI Too Large"},
                    386:        {415, "Unsupported Media Type"},
                    387:        {500, "Internal Server Error"},
                    388:        {501, "Not Implemented"},
                    389:        {502, "Bad Gateway"},
                    390:        {503, "Service Unavailable"},
                    391:        {504, "Gateway Time-out"},
                    392:        {505, "HTTP Version not supported"},
                    393:        {0,   NULL}
                    394: };
                    395: 
                    396: static int sapi_cgi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
                    397: {
                    398:        char buf[SAPI_CGI_MAX_HEADER_LENGTH];
                    399:        sapi_header_struct *h;
                    400:        zend_llist_position pos;
                    401:        zend_bool ignore_status = 0;
                    402:        int response_status = SG(sapi_headers).http_response_code;
                    403: 
                    404:        if (SG(request_info).no_headers == 1) {
                    405:                return  SAPI_HEADER_SENT_SUCCESSFULLY;
                    406:        }
                    407: 
                    408:        if (CGIG(nph) || SG(sapi_headers).http_response_code != 200)
                    409:        {
                    410:                int len;
                    411:                zend_bool has_status = 0;
                    412: 
                    413:                if (CGIG(rfc2616_headers) && SG(sapi_headers).http_status_line) {
                    414:                        char *s;
                    415:                        len = slprintf(buf, SAPI_CGI_MAX_HEADER_LENGTH, "%s\r\n", SG(sapi_headers).http_status_line);
                    416:                        if ((s = strchr(SG(sapi_headers).http_status_line, ' '))) {
                    417:                                response_status = atoi((s + 1));
                    418:                        }
                    419: 
                    420:                        if (len > SAPI_CGI_MAX_HEADER_LENGTH) {
                    421:                                len = SAPI_CGI_MAX_HEADER_LENGTH;
                    422:                        }
                    423: 
                    424:                } else {
                    425:                        char *s;
                    426: 
                    427:                        if (SG(sapi_headers).http_status_line &&
                    428:                                (s = strchr(SG(sapi_headers).http_status_line, ' ')) != 0 &&
                    429:                                (s - SG(sapi_headers).http_status_line) >= 5 &&
                    430:                                strncasecmp(SG(sapi_headers).http_status_line, "HTTP/", 5) == 0
                    431:                        ) {
                    432:                                len = slprintf(buf, sizeof(buf), "Status:%s\r\n", s);
                    433:                                response_status = atoi((s + 1));
                    434:                        } else {
                    435:                                h = (sapi_header_struct*)zend_llist_get_first_ex(&sapi_headers->headers, &pos);
                    436:                                while (h) {
                    437:                                        if (h->header_len > sizeof("Status:")-1 &&
                    438:                                                strncasecmp(h->header, "Status:", sizeof("Status:")-1) == 0
                    439:                                        ) {
                    440:                                                has_status = 1;
                    441:                                                break;
                    442:                                        }
                    443:                                        h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
                    444:                                }
                    445:                                if (!has_status) {
                    446:                                        http_error *err = (http_error*)http_error_codes;
                    447: 
                    448:                                        while (err->code != 0) {
                    449:                                                if (err->code == SG(sapi_headers).http_response_code) {
                    450:                                                        break;
                    451:                                                }
                    452:                                                err++;
                    453:                                        }
                    454:                                        if (err->msg) {
                    455:                                                len = slprintf(buf, sizeof(buf), "Status: %d %s\r\n", SG(sapi_headers).http_response_code, err->msg);
                    456:                                        } else {
                    457:                                                len = slprintf(buf, sizeof(buf), "Status: %d\r\n", SG(sapi_headers).http_response_code);
                    458:                                        }
                    459:                                }
                    460:                        }
                    461:                }
                    462: 
                    463:                if (!has_status) {
                    464:                        PHPWRITE_H(buf, len);
                    465:                        ignore_status = 1;
                    466:                }
                    467:        }
                    468: 
                    469:        h = (sapi_header_struct*)zend_llist_get_first_ex(&sapi_headers->headers, &pos);
                    470:        while (h) {
                    471:                /* prevent CRLFCRLF */
                    472:                if (h->header_len) {
                    473:                        if (h->header_len > sizeof("Status:")-1 && 
                    474:                                strncasecmp(h->header, "Status:", sizeof("Status:")-1) == 0
                    475:                        ) {
                    476:                                if (!ignore_status) {
                    477:                                        ignore_status = 1;
                    478:                                        PHPWRITE_H(h->header, h->header_len);
                    479:                                        PHPWRITE_H("\r\n", 2);
                    480:                                }
                    481:                        } else if (response_status == 304 && h->header_len > sizeof("Content-Type:")-1 &&
                    482:                                strncasecmp(h->header, "Content-Type:", sizeof("Content-Type:")-1) == 0
                    483:                        ) {
                    484:                                h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
                    485:                                continue;
                    486:                        } else {
                    487:                                PHPWRITE_H(h->header, h->header_len);
                    488:                                PHPWRITE_H("\r\n", 2);
                    489:                        }
                    490:                }
                    491:                h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
                    492:        }
                    493:        PHPWRITE_H("\r\n", 2);
                    494: 
                    495:        return SAPI_HEADER_SENT_SUCCESSFULLY;
                    496: }
                    497: 
                    498: #ifndef STDIN_FILENO
                    499: # define STDIN_FILENO 0
                    500: #endif
                    501: 
                    502: static int sapi_cgi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
                    503: {
                    504:        uint read_bytes = 0;
                    505:        int tmp_read_bytes;
                    506: 
                    507:        count_bytes = MIN(count_bytes, (uint) SG(request_info).content_length - SG(read_post_bytes));
                    508:        while (read_bytes < count_bytes) {
1.1.1.2 ! misho     509:                tmp_read_bytes = read(STDIN_FILENO, buffer + read_bytes, count_bytes - read_bytes);
        !           510:                if (tmp_read_bytes <= 0) {
        !           511:                        break;
1.1       misho     512:                }
1.1.1.2 ! misho     513:                read_bytes += tmp_read_bytes;
        !           514:        }
        !           515:        return read_bytes;
        !           516: }
        !           517: 
        !           518: static int sapi_fcgi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
        !           519: {
        !           520:        uint read_bytes = 0;
        !           521:        int tmp_read_bytes;
        !           522:        fcgi_request *request = (fcgi_request*) SG(server_context);
        !           523: 
        !           524:        count_bytes = MIN(count_bytes, (uint) SG(request_info).content_length - SG(read_post_bytes));
        !           525:        while (read_bytes < count_bytes) {
        !           526:                tmp_read_bytes = fcgi_read(request, buffer + read_bytes, count_bytes - read_bytes);
1.1       misho     527:                if (tmp_read_bytes <= 0) {
                    528:                        break;
                    529:                }
                    530:                read_bytes += tmp_read_bytes;
                    531:        }
                    532:        return read_bytes;
                    533: }
                    534: 
1.1.1.2 ! misho     535: static char *sapi_cgi_getenv(char *name, size_t name_len TSRMLS_DC)
        !           536: {
        !           537:        return getenv(name);
        !           538: }
        !           539: 
        !           540: static char *sapi_fcgi_getenv(char *name, size_t name_len TSRMLS_DC)
1.1       misho     541: {
                    542:        /* when php is started by mod_fastcgi, no regular environment
                    543:         * is provided to PHP.  It is always sent to PHP at the start
                    544:         * of a request.  So we have to do our own lookup to get env
                    545:         * vars.  This could probably be faster somehow.  */
1.1.1.2 ! misho     546:        fcgi_request *request = (fcgi_request*) SG(server_context);
        !           547:        char *ret = fcgi_getenv(request, name, name_len);
        !           548: 
        !           549:        if (ret) return ret;
1.1       misho     550:        /*  if cgi, or fastcgi and not found in fcgi env
                    551:                check the regular environment */
                    552:        return getenv(name);
                    553: }
                    554: 
1.1.1.2 ! misho     555: static char *_sapi_cgi_putenv(char *name, int name_len, char *value)
1.1       misho     556: {
                    557: #if !HAVE_SETENV || !HAVE_UNSETENV
                    558:        int len;
                    559:        char *buf;
                    560: #endif
                    561: 
                    562: #if HAVE_SETENV
                    563:        if (value) {
                    564:                setenv(name, value, 1);
                    565:        }
                    566: #endif
                    567: #if HAVE_UNSETENV
                    568:        if (!value) {
                    569:                unsetenv(name);
                    570:        }
                    571: #endif
                    572: 
                    573: #if !HAVE_SETENV || !HAVE_UNSETENV
                    574:        /*  if cgi, or fastcgi and not found in fcgi env
                    575:                check the regular environment
                    576:                this leaks, but it's only cgi anyway, we'll fix
                    577:                it for 5.0
                    578:        */
                    579:        len = name_len + (value ? strlen(value) : 0) + sizeof("=") + 2;
                    580:        buf = (char *) malloc(len);
                    581:        if (buf == NULL) {
                    582:                return getenv(name);
                    583:        }
                    584: #endif
                    585: #if !HAVE_SETENV
                    586:        if (value) {
                    587:                len = slprintf(buf, len - 1, "%s=%s", name, value);
                    588:                putenv(buf);
                    589:        }
                    590: #endif
                    591: #if !HAVE_UNSETENV
                    592:        if (!value) {
                    593:                len = slprintf(buf, len - 1, "%s=", name);
                    594:                putenv(buf);
                    595:        }
                    596: #endif
                    597:        return getenv(name);
                    598: }
                    599: 
                    600: static char *sapi_cgi_read_cookies(TSRMLS_D)
                    601: {
1.1.1.2 ! misho     602:        return getenv("HTTP_COOKIE");
        !           603: }
        !           604: 
        !           605: static char *sapi_fcgi_read_cookies(TSRMLS_D)
        !           606: {
        !           607:        fcgi_request *request = (fcgi_request*) SG(server_context);
        !           608: 
        !           609:        return FCGI_GETENV(request, "HTTP_COOKIE");
        !           610: }
        !           611: 
        !           612: static void cgi_php_load_env_var(char *var, unsigned int var_len, char *val, unsigned int val_len, void *arg TSRMLS_DC)
        !           613: {
        !           614:        zval *array_ptr = (zval*)arg;   
        !           615:        int filter_arg = (array_ptr == PG(http_globals)[TRACK_VARS_ENV])?PARSE_ENV:PARSE_SERVER;
        !           616:        unsigned int new_val_len;
        !           617: 
        !           618:        if (sapi_module.input_filter(filter_arg, var, &val, strlen(val), &new_val_len TSRMLS_CC)) {
        !           619:                php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC);
        !           620:        }
1.1       misho     621: }
                    622: 
1.1.1.2 ! misho     623: static void cgi_php_import_environment_variables(zval *array_ptr TSRMLS_DC)
1.1       misho     624: {
                    625:        if (PG(http_globals)[TRACK_VARS_ENV] &&
                    626:                array_ptr != PG(http_globals)[TRACK_VARS_ENV] &&
                    627:                Z_TYPE_P(PG(http_globals)[TRACK_VARS_ENV]) == IS_ARRAY &&
                    628:                zend_hash_num_elements(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_ENV])) > 0
                    629:        ) {
                    630:                zval_dtor(array_ptr);
                    631:                *array_ptr = *PG(http_globals)[TRACK_VARS_ENV];
                    632:                INIT_PZVAL(array_ptr);
                    633:                zval_copy_ctor(array_ptr);
                    634:                return;
                    635:        } else if (PG(http_globals)[TRACK_VARS_SERVER] &&
                    636:                array_ptr != PG(http_globals)[TRACK_VARS_SERVER] &&
                    637:                Z_TYPE_P(PG(http_globals)[TRACK_VARS_SERVER]) == IS_ARRAY &&
                    638:                zend_hash_num_elements(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER])) > 0
                    639:        ) {
                    640:                zval_dtor(array_ptr);
                    641:                *array_ptr = *PG(http_globals)[TRACK_VARS_SERVER];
                    642:                INIT_PZVAL(array_ptr);
                    643:                zval_copy_ctor(array_ptr);
                    644:                return;
                    645:        }
                    646: 
                    647:        /* call php's original import as a catch-all */
                    648:        php_php_import_environment_variables(array_ptr TSRMLS_CC);
                    649: 
                    650:        if (fcgi_is_fastcgi()) {
                    651:                fcgi_request *request = (fcgi_request*) SG(server_context);
1.1.1.2 ! misho     652:                fcgi_loadenv(request, cgi_php_load_env_var, array_ptr TSRMLS_CC);
1.1       misho     653:        }
                    654: }
                    655: 
                    656: static void sapi_cgi_register_variables(zval *track_vars_array TSRMLS_DC)
                    657: {
                    658:        unsigned int php_self_len;
                    659:        char *php_self;
                    660: 
                    661:        /* In CGI mode, we consider the environment to be a part of the server
                    662:         * variables
                    663:         */
                    664:        php_import_environment_variables(track_vars_array TSRMLS_CC);
                    665: 
                    666:        if (CGIG(fix_pathinfo)) {
                    667:                char *script_name = SG(request_info).request_uri;
1.1.1.2 ! misho     668:                char *path_info;
        !           669:                int free_php_self;
        !           670:                ALLOCA_FLAG(use_heap)
1.1       misho     671: 
1.1.1.2 ! misho     672:                if (fcgi_is_fastcgi()) {
        !           673:                        fcgi_request *request = (fcgi_request*) SG(server_context);
1.1       misho     674: 
1.1.1.2 ! misho     675:                        path_info = FCGI_GETENV(request, "PATH_INFO");
        !           676:                } else {
        !           677:                        path_info = getenv("PATH_INFO");
1.1       misho     678:                }
1.1.1.2 ! misho     679: 
1.1       misho     680:                if (path_info) {
1.1.1.2 ! misho     681:                        unsigned int path_info_len = strlen(path_info);
        !           682: 
        !           683:                        if (script_name) {
        !           684:                                unsigned int script_name_len = strlen(script_name);
        !           685: 
        !           686:                                php_self_len = script_name_len + path_info_len;
        !           687:                                php_self = do_alloca(php_self_len + 1, use_heap);
        !           688:                                memcpy(php_self, script_name, script_name_len + 1);
        !           689:                                memcpy(php_self + script_name_len, path_info, path_info_len + 1);
        !           690:                                free_php_self = 1;
        !           691:                        }  else {
        !           692:                                php_self = path_info;
        !           693:                                php_self_len = path_info_len;
        !           694:                                free_php_self = 0;
        !           695:                        }
        !           696:                } else if (script_name) {
        !           697:                        php_self = script_name;
        !           698:                        php_self_len = strlen(script_name);
        !           699:                        free_php_self = 0;
        !           700:                } else {
        !           701:                        php_self = "";
        !           702:                        php_self_len = 0;
        !           703:                        free_php_self = 0;
1.1       misho     704:                }
                    705: 
                    706:                /* Build the special-case PHP_SELF variable for the CGI version */
                    707:                if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &php_self, php_self_len, &php_self_len TSRMLS_CC)) {
                    708:                        php_register_variable_safe("PHP_SELF", php_self, php_self_len, track_vars_array TSRMLS_CC);
                    709:                }
1.1.1.2 ! misho     710:                if (free_php_self) {
        !           711:                        free_alloca(php_self, use_heap);
        !           712:                }
1.1       misho     713:        } else {
                    714:                php_self = SG(request_info).request_uri ? SG(request_info).request_uri : "";
                    715:                php_self_len = strlen(php_self);
                    716:                if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &php_self, php_self_len, &php_self_len TSRMLS_CC)) {
                    717:                        php_register_variable_safe("PHP_SELF", php_self, php_self_len, track_vars_array TSRMLS_CC);
                    718:                }
                    719:        }
                    720: }
                    721: 
1.1.1.2 ! misho     722: static void sapi_cgi_log_message(char *message TSRMLS_DC)
1.1       misho     723: {
                    724:        if (fcgi_is_fastcgi() && CGIG(fcgi_logging)) {
                    725:                fcgi_request *request;
                    726: 
                    727:                request = (fcgi_request*) SG(server_context);
                    728:                if (request) {
                    729:                        int len = strlen(message);
                    730:                        char *buf = malloc(len+2);
                    731: 
                    732:                        memcpy(buf, message, len);
                    733:                        memcpy(buf + len, "\n", sizeof("\n"));
                    734:                        fcgi_write(request, FCGI_STDERR, buf, len+1);
                    735:                        free(buf);
                    736:                } else {
                    737:                        fprintf(stderr, "%s\n", message);
                    738:                }
                    739:                /* ignore return code */
                    740:        } else {
                    741:                fprintf(stderr, "%s\n", message);
                    742:        }
                    743: }
                    744: 
                    745: /* {{{ php_cgi_ini_activate_user_config
                    746:  */
                    747: static void php_cgi_ini_activate_user_config(char *path, int path_len, const char *doc_root, int doc_root_len, int start TSRMLS_DC)
                    748: {
                    749:        char *ptr;
                    750:        user_config_cache_entry *new_entry, *entry;
                    751:        time_t request_time = sapi_get_request_time(TSRMLS_C);
                    752: 
                    753:        /* Find cached config entry: If not found, create one */
                    754:        if (zend_hash_find(&CGIG(user_config_cache), path, path_len + 1, (void **) &entry) == FAILURE) {
                    755:                new_entry = pemalloc(sizeof(user_config_cache_entry), 1);
                    756:                new_entry->expires = 0;
                    757:                new_entry->user_config = (HashTable *) pemalloc(sizeof(HashTable), 1);
                    758:                zend_hash_init(new_entry->user_config, 0, NULL, (dtor_func_t) config_zval_dtor, 1);
                    759:                zend_hash_update(&CGIG(user_config_cache), path, path_len + 1, new_entry, sizeof(user_config_cache_entry), (void **) &entry);
                    760:                free(new_entry);
                    761:        }
                    762: 
                    763:        /* Check whether cache entry has expired and rescan if it is */
                    764:        if (request_time > entry->expires) {
                    765:                char *real_path = NULL;
                    766:                int real_path_len;
                    767:                char *s1, *s2;
                    768:                int s_len;
                    769: 
                    770:                /* Clear the expired config */
                    771:                zend_hash_clean(entry->user_config);
                    772: 
                    773:                if (!IS_ABSOLUTE_PATH(path, path_len)) {
                    774:                        real_path = tsrm_realpath(path, NULL TSRMLS_CC);
                    775:                        if (real_path == NULL) {
                    776:                                return;
                    777:                        }
                    778:                        real_path_len = strlen(real_path);
                    779:                        path = real_path;
                    780:                        path_len = real_path_len;
                    781:                }
                    782: 
                    783:                if (path_len > doc_root_len) {
                    784:                        s1 = (char *) doc_root;
                    785:                        s2 = path;
                    786:                        s_len = doc_root_len;
                    787:                } else {
                    788:                        s1 = path;
                    789:                        s2 = (char *) doc_root;
                    790:                        s_len = path_len;
                    791:                }
                    792: 
                    793:                /* we have to test if path is part of DOCUMENT_ROOT.
                    794:                  if it is inside the docroot, we scan the tree up to the docroot 
                    795:                        to find more user.ini, if not we only scan the current path.
                    796:                  */
                    797: #ifdef PHP_WIN32
                    798:                if (strnicmp(s1, s2, s_len) == 0) {
                    799: #else 
                    800:                if (strncmp(s1, s2, s_len) == 0) {
                    801: #endif
                    802:                        ptr = s2 + start;  /* start is the point where doc_root ends! */
                    803:                        while ((ptr = strchr(ptr, DEFAULT_SLASH)) != NULL) {
                    804:                                *ptr = 0;
                    805:                                php_parse_user_ini_file(path, PG(user_ini_filename), entry->user_config TSRMLS_CC);
                    806:                                *ptr = '/';
                    807:                                ptr++;
                    808:                        }
                    809:                } else {
                    810:                        php_parse_user_ini_file(path, PG(user_ini_filename), entry->user_config TSRMLS_CC);
                    811:                }
                    812: 
                    813:                if (real_path) {
                    814:                        free(real_path);
                    815:                }
                    816:                entry->expires = request_time + PG(user_ini_cache_ttl);
                    817:        }
                    818: 
                    819:        /* Activate ini entries with values from the user config hash */
                    820:        php_ini_activate_config(entry->user_config, PHP_INI_PERDIR, PHP_INI_STAGE_HTACCESS TSRMLS_CC);
                    821: }
                    822: /* }}} */
                    823: 
                    824: static int sapi_cgi_activate(TSRMLS_D)
                    825: {
                    826:        char *path, *doc_root, *server_name;
                    827:        uint path_len, doc_root_len, server_name_len;
                    828: 
                    829:        /* PATH_TRANSLATED should be defined at this stage but better safe than sorry :) */
                    830:        if (!SG(request_info).path_translated) {
                    831:                return FAILURE;
                    832:        }
                    833: 
                    834:        if (php_ini_has_per_host_config()) {
                    835:                /* Activate per-host-system-configuration defined in php.ini and stored into configuration_hash during startup */
1.1.1.2 ! misho     836:                if (fcgi_is_fastcgi()) {
        !           837:                        fcgi_request *request = (fcgi_request*) SG(server_context);
        !           838: 
        !           839:                        server_name = FCGI_GETENV(request, "SERVER_NAME");
        !           840:                } else {
        !           841:                        server_name = getenv("SERVER_NAME");
        !           842:                }
1.1       misho     843:                /* SERVER_NAME should also be defined at this stage..but better check it anyway */
                    844:                if (server_name) {
                    845:                        server_name_len = strlen(server_name);
                    846:                        server_name = estrndup(server_name, server_name_len);
                    847:                        zend_str_tolower(server_name, server_name_len);
                    848:                        php_ini_activate_per_host_config(server_name, server_name_len + 1 TSRMLS_CC);
                    849:                        efree(server_name);
                    850:                }
                    851:        }
                    852: 
                    853:        if (php_ini_has_per_dir_config() ||
                    854:                (PG(user_ini_filename) && *PG(user_ini_filename))
                    855:        ) {
                    856:                /* Prepare search path */
                    857:                path_len = strlen(SG(request_info).path_translated);
                    858: 
                    859:                /* Make sure we have trailing slash! */
                    860:                if (!IS_SLASH(SG(request_info).path_translated[path_len])) {
                    861:                        path = emalloc(path_len + 2);
                    862:                        memcpy(path, SG(request_info).path_translated, path_len + 1);
                    863:                        path_len = zend_dirname(path, path_len);
                    864:                        path[path_len++] = DEFAULT_SLASH;
                    865:                } else {
                    866:                        path = estrndup(SG(request_info).path_translated, path_len);
                    867:                        path_len = zend_dirname(path, path_len);
                    868:                }
                    869:                path[path_len] = 0;
                    870: 
                    871:                /* Activate per-dir-system-configuration defined in php.ini and stored into configuration_hash during startup */
                    872:                php_ini_activate_per_dir_config(path, path_len TSRMLS_CC); /* Note: for global settings sake we check from root to path */
                    873: 
                    874:                /* Load and activate user ini files in path starting from DOCUMENT_ROOT */
                    875:                if (PG(user_ini_filename) && *PG(user_ini_filename)) {
1.1.1.2 ! misho     876:                        if (fcgi_is_fastcgi()) {
        !           877:                                fcgi_request *request = (fcgi_request*) SG(server_context);
        !           878: 
        !           879:                                doc_root = FCGI_GETENV(request, "DOCUMENT_ROOT");
        !           880:                        } else {
        !           881:                                doc_root = getenv("DOCUMENT_ROOT");
        !           882:                        }
        !           883: 
1.1       misho     884:                        /* DOCUMENT_ROOT should also be defined at this stage..but better check it anyway */
                    885:                        if (doc_root) {
                    886:                                doc_root_len = strlen(doc_root);
                    887:                                if (doc_root_len > 0 && IS_SLASH(doc_root[doc_root_len - 1])) {
                    888:                                        --doc_root_len;
                    889:                                }
                    890: #ifdef PHP_WIN32
                    891:                                /* paths on windows should be case-insensitive */
                    892:                                doc_root = estrndup(doc_root, doc_root_len);
                    893:                                zend_str_tolower(doc_root, doc_root_len);
                    894: #endif
                    895:                                php_cgi_ini_activate_user_config(path, path_len, doc_root, doc_root_len, doc_root_len - 1 TSRMLS_CC);
                    896:                        }
                    897:                }
                    898: 
                    899: #ifdef PHP_WIN32
                    900:                efree(doc_root);
                    901: #endif
                    902:                efree(path);
                    903:        }
                    904: 
                    905:        return SUCCESS;
                    906: }
                    907: 
                    908: static int sapi_cgi_deactivate(TSRMLS_D)
                    909: {
                    910:        /* flush only when SAPI was started. The reasons are:
                    911:                1. SAPI Deactivate is called from two places: module init and request shutdown
                    912:                2. When the first call occurs and the request is not set up, flush fails on FastCGI.
                    913:        */
                    914:        if (SG(sapi_started)) {
                    915:                if (fcgi_is_fastcgi()) {
                    916:                        if (
                    917: #ifndef PHP_WIN32
                    918:                                !parent &&
                    919: #endif
                    920:                                !fcgi_finish_request((fcgi_request*)SG(server_context), 0)) {
                    921:                                php_handle_aborted_connection();
                    922:                        }
                    923:                } else {
1.1.1.2 ! misho     924:                        sapi_cgi_flush(SG(server_context));
1.1       misho     925:                }
                    926:        }
                    927:        return SUCCESS;
                    928: }
                    929: 
                    930: static int php_cgi_startup(sapi_module_struct *sapi_module)
                    931: {
                    932:        if (php_module_startup(sapi_module, &cgi_module_entry, 1) == FAILURE) {
                    933:                return FAILURE;
                    934:        }
                    935:        return SUCCESS;
                    936: }
                    937: 
                    938: /* {{{ sapi_module_struct cgi_sapi_module
                    939:  */
                    940: static sapi_module_struct cgi_sapi_module = {
                    941:        "cgi-fcgi",                                             /* name */
                    942:        "CGI/FastCGI",                                  /* pretty name */
                    943: 
                    944:        php_cgi_startup,                                /* startup */
                    945:        php_module_shutdown_wrapper,    /* shutdown */
                    946: 
                    947:        sapi_cgi_activate,                              /* activate */
                    948:        sapi_cgi_deactivate,                    /* deactivate */
                    949: 
1.1.1.2 ! misho     950:        sapi_cgi_ub_write,                              /* unbuffered write */
        !           951:        sapi_cgi_flush,                                 /* flush */
1.1       misho     952:        NULL,                                                   /* get uid */
1.1.1.2 ! misho     953:        sapi_cgi_getenv,                                /* getenv */
1.1       misho     954: 
                    955:        php_error,                                              /* error handler */
                    956: 
                    957:        NULL,                                                   /* header handler */
                    958:        sapi_cgi_send_headers,                  /* send headers handler */
                    959:        NULL,                                                   /* send header handler */
                    960: 
                    961:        sapi_cgi_read_post,                             /* read POST data */
                    962:        sapi_cgi_read_cookies,                  /* read Cookies */
                    963: 
                    964:        sapi_cgi_register_variables,    /* register server variables */
                    965:        sapi_cgi_log_message,                   /* Log message */
                    966:        NULL,                                                   /* Get request time */
                    967:        NULL,                                                   /* Child terminate */
                    968: 
                    969:        STANDARD_SAPI_MODULE_PROPERTIES
                    970: };
                    971: /* }}} */
                    972: 
                    973: /* {{{ arginfo ext/standard/dl.c */
                    974: ZEND_BEGIN_ARG_INFO(arginfo_dl, 0)
                    975:        ZEND_ARG_INFO(0, extension_filename)
                    976: ZEND_END_ARG_INFO()
                    977: /* }}} */
                    978: 
                    979: static const zend_function_entry additional_functions[] = {
                    980:        ZEND_FE(dl, arginfo_dl)
                    981:        {NULL, NULL, NULL}
                    982: };
                    983: 
                    984: /* {{{ php_cgi_usage
                    985:  */
                    986: static void php_cgi_usage(char *argv0)
                    987: {
                    988:        char *prog;
                    989: 
                    990:        prog = strrchr(argv0, '/');
                    991:        if (prog) {
                    992:                prog++;
                    993:        } else {
                    994:                prog = "php";
                    995:        }
                    996: 
                    997:        php_printf(     "Usage: %s [-q] [-h] [-s] [-v] [-i] [-f <file>]\n"
                    998:                                "       %s <file> [args...]\n"
                    999:                                "  -a               Run interactively\n"
                   1000:                                "  -b <address:port>|<port> Bind Path for external FASTCGI Server mode\n"
                   1001:                                "  -C               Do not chdir to the script's directory\n"
                   1002:                                "  -c <path>|<file> Look for php.ini file in this directory\n"
                   1003:                                "  -n               No php.ini file will be used\n"
                   1004:                                "  -d foo[=bar]     Define INI entry foo with value 'bar'\n"
                   1005:                                "  -e               Generate extended information for debugger/profiler\n"
                   1006:                                "  -f <file>        Parse <file>.  Implies `-q'\n"
                   1007:                                "  -h               This help\n"
                   1008:                                "  -i               PHP information\n"
                   1009:                                "  -l               Syntax check only (lint)\n"
                   1010:                                "  -m               Show compiled in modules\n"
                   1011:                                "  -q               Quiet-mode.  Suppress HTTP Header output.\n"
                   1012:                                "  -s               Display colour syntax highlighted source.\n"
                   1013:                                "  -v               Version number\n"
                   1014:                                "  -w               Display source with stripped comments and whitespace.\n"
                   1015:                                "  -z <file>        Load Zend extension <file>.\n"
                   1016:                                "  -T <count>       Measure execution time of script repeated <count> times.\n",
                   1017:                                prog, prog);
                   1018: }
                   1019: /* }}} */
                   1020: 
                   1021: /* {{{ is_valid_path
                   1022:  *
                   1023:  * some server configurations allow '..' to slip through in the
                   1024:  * translated path.   We'll just refuse to handle such a path.
                   1025:  */
                   1026: static int is_valid_path(const char *path)
                   1027: {
1.1.1.2 ! misho    1028:        const char *p = path;
1.1       misho    1029: 
1.1.1.2 ! misho    1030:        if (UNEXPECTED(!p)) {
1.1       misho    1031:                return 0;
                   1032:        }
1.1.1.2 ! misho    1033:        if (UNEXPECTED(*p == '.') && *(p+1) == '.' && (!*(p+2) || IS_SLASH(*(p+2)))) {
        !          1034:                return 0;
        !          1035:        }
        !          1036:        while (*p) {
        !          1037:                if (IS_SLASH(*p)) {
        !          1038:                        p++;
        !          1039:                        if (UNEXPECTED(*p == '.')) {
        !          1040:                                p++;
        !          1041:                                if (UNEXPECTED(*p == '.')) {
        !          1042:                                        p++;
        !          1043:                                        if (UNEXPECTED(!*p) || UNEXPECTED(IS_SLASH(*p))) {
        !          1044:                                                return 0;
        !          1045:                                        }                                                                                       
        !          1046:                                }
1.1       misho    1047:                        }
                   1048:                }
1.1.1.2 ! misho    1049:                p++;
1.1       misho    1050:        }
                   1051:        return 1;
                   1052: }
                   1053: /* }}} */
                   1054: 
1.1.1.2 ! misho    1055: #define CGI_GETENV(name) \
        !          1056:        ((request) ? \
        !          1057:                FCGI_GETENV(request, name) : \
        !          1058:        getenv(name))
        !          1059: 
        !          1060: #define CGI_PUTENV(name, value) \
        !          1061:        ((request) ? \
        !          1062:                FCGI_PUTENV(request, name, value) : \
        !          1063:                _sapi_cgi_putenv(name, sizeof(name)-1, value))
        !          1064: 
1.1       misho    1065: /* {{{ init_request_info
                   1066: 
                   1067:   initializes request_info structure
                   1068: 
                   1069:   specificly in this section we handle proper translations
                   1070:   for:
                   1071: 
                   1072:   PATH_INFO
                   1073:        derived from the portion of the URI path following
                   1074:        the script name but preceding any query data
                   1075:        may be empty
                   1076: 
                   1077:   PATH_TRANSLATED
                   1078:     derived by taking any path-info component of the
                   1079:        request URI and performing any virtual-to-physical
                   1080:        translation appropriate to map it onto the server's
                   1081:        document repository structure
                   1082: 
                   1083:        empty if PATH_INFO is empty
                   1084: 
                   1085:        The env var PATH_TRANSLATED **IS DIFFERENT** than the
                   1086:        request_info.path_translated variable, the latter should
                   1087:        match SCRIPT_FILENAME instead.
                   1088: 
                   1089:   SCRIPT_NAME
                   1090:     set to a URL path that could identify the CGI script
                   1091:        rather than the interpreter.  PHP_SELF is set to this
                   1092: 
                   1093:   REQUEST_URI
                   1094:     uri section following the domain:port part of a URI
                   1095: 
                   1096:   SCRIPT_FILENAME
                   1097:     The virtual-to-physical translation of SCRIPT_NAME (as per
                   1098:        PATH_TRANSLATED)
                   1099: 
                   1100:   These settings are documented at
                   1101:   http://cgi-spec.golux.com/
                   1102: 
                   1103: 
                   1104:   Based on the following URL request:
                   1105: 
                   1106:   http://localhost/info.php/test?a=b
                   1107: 
                   1108:   should produce, which btw is the same as if
                   1109:   we were running under mod_cgi on apache (ie. not
                   1110:   using ScriptAlias directives):
                   1111: 
                   1112:   PATH_INFO=/test
                   1113:   PATH_TRANSLATED=/docroot/test
                   1114:   SCRIPT_NAME=/info.php
                   1115:   REQUEST_URI=/info.php/test?a=b
                   1116:   SCRIPT_FILENAME=/docroot/info.php
                   1117:   QUERY_STRING=a=b
                   1118: 
                   1119:   but what we get is (cgi/mod_fastcgi under apache):
                   1120: 
                   1121:   PATH_INFO=/info.php/test
                   1122:   PATH_TRANSLATED=/docroot/info.php/test
                   1123:   SCRIPT_NAME=/php/php-cgi  (from the Action setting I suppose)
                   1124:   REQUEST_URI=/info.php/test?a=b
                   1125:   SCRIPT_FILENAME=/path/to/php/bin/php-cgi  (Action setting translated)
                   1126:   QUERY_STRING=a=b
                   1127: 
                   1128:   Comments in the code below refer to using the above URL in a request
                   1129: 
                   1130:  */
1.1.1.2 ! misho    1131: static void init_request_info(fcgi_request *request TSRMLS_DC)
1.1       misho    1132: {
1.1.1.2 ! misho    1133:        char *env_script_filename = CGI_GETENV("SCRIPT_FILENAME");
        !          1134:        char *env_path_translated = CGI_GETENV("PATH_TRANSLATED");
1.1       misho    1135:        char *script_path_translated = env_script_filename;
                   1136: 
                   1137:        /* some broken servers do not have script_filename or argv0
                   1138:         * an example, IIS configured in some ways.  then they do more
                   1139:         * broken stuff and set path_translated to the cgi script location */
                   1140:        if (!script_path_translated && env_path_translated) {
                   1141:                script_path_translated = env_path_translated;
                   1142:        }
                   1143: 
                   1144:        /* initialize the defaults */
                   1145:        SG(request_info).path_translated = NULL;
                   1146:        SG(request_info).request_method = NULL;
                   1147:        SG(request_info).proto_num = 1000;
                   1148:        SG(request_info).query_string = NULL;
                   1149:        SG(request_info).request_uri = NULL;
                   1150:        SG(request_info).content_type = NULL;
                   1151:        SG(request_info).content_length = 0;
                   1152:        SG(sapi_headers).http_response_code = 200;
                   1153: 
                   1154:        /* script_path_translated being set is a good indication that
                   1155:         * we are running in a cgi environment, since it is always
                   1156:         * null otherwise.  otherwise, the filename
                   1157:         * of the script will be retreived later via argc/argv */
                   1158:        if (script_path_translated) {
                   1159:                const char *auth;
1.1.1.2 ! misho    1160:                char *content_length = CGI_GETENV("CONTENT_LENGTH");
        !          1161:                char *content_type = CGI_GETENV("CONTENT_TYPE");
        !          1162:                char *env_path_info = CGI_GETENV("PATH_INFO");
        !          1163:                char *env_script_name = CGI_GETENV("SCRIPT_NAME");
1.1       misho    1164: 
1.1.1.2 ! misho    1165: #ifdef PHP_WIN32
1.1       misho    1166:                /* Hack for buggy IIS that sets incorrect PATH_INFO */
1.1.1.2 ! misho    1167:                char *env_server_software = CGI_GETENV("SERVER_SOFTWARE");
        !          1168: 
1.1       misho    1169:                if (env_server_software &&
                   1170:                        env_script_name &&
                   1171:                        env_path_info &&
                   1172:                        strncmp(env_server_software, "Microsoft-IIS", sizeof("Microsoft-IIS")-1) == 0 &&
                   1173:                        strncmp(env_path_info, env_script_name, strlen(env_script_name)) == 0
                   1174:                ) {
1.1.1.2 ! misho    1175:                        env_path_info = CGI_PUTENV("ORIG_PATH_INFO", env_path_info);
1.1       misho    1176:                        env_path_info += strlen(env_script_name);
                   1177:                        if (*env_path_info == 0) {
                   1178:                                env_path_info = NULL;
                   1179:                        }
1.1.1.2 ! misho    1180:                        env_path_info = CGI_PUTENV("PATH_INFO", env_path_info);
1.1       misho    1181:                }
1.1.1.2 ! misho    1182: #endif
1.1       misho    1183: 
                   1184:                if (CGIG(fix_pathinfo)) {
                   1185:                        struct stat st;
                   1186:                        char *real_path = NULL;
1.1.1.2 ! misho    1187:                        char *env_redirect_url = CGI_GETENV("REDIRECT_URL");
        !          1188:                        char *env_document_root = CGI_GETENV("DOCUMENT_ROOT");
1.1       misho    1189:                        char *orig_path_translated = env_path_translated;
                   1190:                        char *orig_path_info = env_path_info;
                   1191:                        char *orig_script_name = env_script_name;
                   1192:                        char *orig_script_filename = env_script_filename;
                   1193:                        int script_path_translated_len;
                   1194: 
                   1195:                        if (!env_document_root && PG(doc_root)) {
1.1.1.2 ! misho    1196:                                env_document_root = CGI_PUTENV("DOCUMENT_ROOT", PG(doc_root));
1.1       misho    1197:                                /* fix docroot */
                   1198:                                TRANSLATE_SLASHES(env_document_root);
                   1199:                        }
                   1200: 
                   1201:                        if (env_path_translated != NULL && env_redirect_url != NULL &&
                   1202:                            env_path_translated != script_path_translated &&
                   1203:                            strcmp(env_path_translated, script_path_translated) != 0) {
                   1204:                                /*
                   1205:                                 * pretty much apache specific.  If we have a redirect_url
                   1206:                                 * then our script_filename and script_name point to the
                   1207:                                 * php executable
                   1208:                                 */
                   1209:                                script_path_translated = env_path_translated;
                   1210:                                /* we correct SCRIPT_NAME now in case we don't have PATH_INFO */
                   1211:                                env_script_name = env_redirect_url;
                   1212:                        }
                   1213: 
                   1214: #ifdef __riscos__
                   1215:                        /* Convert path to unix format*/
                   1216:                        __riscosify_control |= __RISCOSIFY_DONT_CHECK_DIR;
                   1217:                        script_path_translated = __unixify(script_path_translated, 0, NULL, 1, 0);
                   1218: #endif
                   1219: 
                   1220:                        /*
                   1221:                         * if the file doesn't exist, try to extract PATH_INFO out
                   1222:                         * of it by stat'ing back through the '/'
                   1223:                         * this fixes url's like /info.php/test
                   1224:                         */
                   1225:                        if (script_path_translated &&
                   1226:                                (script_path_translated_len = strlen(script_path_translated)) > 0 &&
                   1227:                                (script_path_translated[script_path_translated_len-1] == '/' ||
                   1228: #ifdef PHP_WIN32
                   1229:                                script_path_translated[script_path_translated_len-1] == '\\' ||
                   1230: #endif
                   1231:                                (real_path = tsrm_realpath(script_path_translated, NULL TSRMLS_CC)) == NULL)
                   1232:                        ) {
                   1233:                                char *pt = estrndup(script_path_translated, script_path_translated_len);
                   1234:                                int len = script_path_translated_len;
                   1235:                                char *ptr;
                   1236: 
                   1237:                                while ((ptr = strrchr(pt, '/')) || (ptr = strrchr(pt, '\\'))) {
                   1238:                                        *ptr = 0;
                   1239:                                        if (stat(pt, &st) == 0 && S_ISREG(st.st_mode)) {
                   1240:                                                /*
                   1241:                                                 * okay, we found the base script!
                   1242:                                                 * work out how many chars we had to strip off;
                   1243:                                                 * then we can modify PATH_INFO
                   1244:                                                 * accordingly
                   1245:                                                 *
                   1246:                                                 * we now have the makings of
                   1247:                                                 * PATH_INFO=/test
                   1248:                                                 * SCRIPT_FILENAME=/docroot/info.php
                   1249:                                                 *
                   1250:                                                 * we now need to figure out what docroot is.
                   1251:                                                 * if DOCUMENT_ROOT is set, this is easy, otherwise,
                   1252:                                                 * we have to play the game of hide and seek to figure
                   1253:                                                 * out what SCRIPT_NAME should be
                   1254:                                                 */
                   1255:                                                int slen = len - strlen(pt);
                   1256:                                                int pilen = env_path_info ? strlen(env_path_info) : 0;
                   1257:                                                char *path_info = env_path_info ? env_path_info + pilen - slen : NULL;
                   1258: 
                   1259:                                                if (orig_path_info != path_info) {
                   1260:                                                        if (orig_path_info) {
                   1261:                                                                char old;
                   1262: 
1.1.1.2 ! misho    1263:                                                                CGI_PUTENV("ORIG_PATH_INFO", orig_path_info);
1.1       misho    1264:                                                                old = path_info[0];
                   1265:                                                                path_info[0] = 0;
                   1266:                                                                if (!orig_script_name ||
                   1267:                                                                        strcmp(orig_script_name, env_path_info) != 0) {
                   1268:                                                                        if (orig_script_name) {
1.1.1.2 ! misho    1269:                                                                                CGI_PUTENV("ORIG_SCRIPT_NAME", orig_script_name);
1.1       misho    1270:                                                                        }
1.1.1.2 ! misho    1271:                                                                        SG(request_info).request_uri = CGI_PUTENV("SCRIPT_NAME", env_path_info);
1.1       misho    1272:                                                                } else {
                   1273:                                                                        SG(request_info).request_uri = orig_script_name;
                   1274:                                                                }
                   1275:                                                                path_info[0] = old;
                   1276:                                                        }
1.1.1.2 ! misho    1277:                                                        env_path_info = CGI_PUTENV("PATH_INFO", path_info);
1.1       misho    1278:                                                }
                   1279:                                                if (!orig_script_filename ||
                   1280:                                                        strcmp(orig_script_filename, pt) != 0) {
                   1281:                                                        if (orig_script_filename) {
1.1.1.2 ! misho    1282:                                                                CGI_PUTENV("ORIG_SCRIPT_FILENAME", orig_script_filename);
1.1       misho    1283:                                                        }
1.1.1.2 ! misho    1284:                                                        script_path_translated = CGI_PUTENV("SCRIPT_FILENAME", pt);
1.1       misho    1285:                                                }
                   1286:                                                TRANSLATE_SLASHES(pt);
                   1287: 
                   1288:                                                /* figure out docroot
                   1289:                                                 * SCRIPT_FILENAME minus SCRIPT_NAME
                   1290:                                                 */
                   1291:                                                if (env_document_root) {
                   1292:                                                        int l = strlen(env_document_root);
                   1293:                                                        int path_translated_len = 0;
                   1294:                                                        char *path_translated = NULL;
                   1295: 
                   1296:                                                        if (l && env_document_root[l - 1] == '/') {
                   1297:                                                                --l;
                   1298:                                                        }
                   1299: 
                   1300:                                                        /* we have docroot, so we should have:
                   1301:                                                         * DOCUMENT_ROOT=/docroot
                   1302:                                                         * SCRIPT_FILENAME=/docroot/info.php
                   1303:                                                         */
                   1304: 
                   1305:                                                        /* PATH_TRANSLATED = DOCUMENT_ROOT + PATH_INFO */
                   1306:                                                        path_translated_len = l + (env_path_info ? strlen(env_path_info) : 0);
                   1307:                                                        path_translated = (char *) emalloc(path_translated_len + 1);
                   1308:                                                        memcpy(path_translated, env_document_root, l);
                   1309:                                                        if (env_path_info) {
                   1310:                                                                memcpy(path_translated + l, env_path_info, (path_translated_len - l));
                   1311:                                                        }
                   1312:                                                        path_translated[path_translated_len] = '\0';
                   1313:                                                        if (orig_path_translated) {
1.1.1.2 ! misho    1314:                                                                CGI_PUTENV("ORIG_PATH_TRANSLATED", orig_path_translated);
1.1       misho    1315:                                                        }
1.1.1.2 ! misho    1316:                                                        env_path_translated = CGI_PUTENV("PATH_TRANSLATED", path_translated);
1.1       misho    1317:                                                        efree(path_translated);
                   1318:                                                } else if (     env_script_name &&
                   1319:                                                                        strstr(pt, env_script_name)
                   1320:                                                ) {
                   1321:                                                        /* PATH_TRANSLATED = PATH_TRANSLATED - SCRIPT_NAME + PATH_INFO */
                   1322:                                                        int ptlen = strlen(pt) - strlen(env_script_name);
                   1323:                                                        int path_translated_len = ptlen + (env_path_info ? strlen(env_path_info) : 0);
                   1324:                                                        char *path_translated = NULL;
                   1325: 
                   1326:                                                        path_translated = (char *) emalloc(path_translated_len + 1);
                   1327:                                                        memcpy(path_translated, pt, ptlen);
                   1328:                                                        if (env_path_info) {
                   1329:                                                                memcpy(path_translated + ptlen, env_path_info, path_translated_len - ptlen);
                   1330:                                                        }
                   1331:                                                        path_translated[path_translated_len] = '\0';
                   1332:                                                        if (orig_path_translated) {
1.1.1.2 ! misho    1333:                                                                CGI_PUTENV("ORIG_PATH_TRANSLATED", orig_path_translated);
1.1       misho    1334:                                                        }
1.1.1.2 ! misho    1335:                                                        env_path_translated = CGI_PUTENV("PATH_TRANSLATED", path_translated);
1.1       misho    1336:                                                        efree(path_translated);
                   1337:                                                }
                   1338:                                                break;
                   1339:                                        }
                   1340:                                }
                   1341:                                if (!ptr) {
                   1342:                                        /*
                   1343:                                         * if we stripped out all the '/' and still didn't find
                   1344:                                         * a valid path... we will fail, badly. of course we would
                   1345:                                         * have failed anyway... we output 'no input file' now.
                   1346:                                         */
                   1347:                                        if (orig_script_filename) {
1.1.1.2 ! misho    1348:                                                CGI_PUTENV("ORIG_SCRIPT_FILENAME", orig_script_filename);
1.1       misho    1349:                                        }
1.1.1.2 ! misho    1350:                                        script_path_translated = CGI_PUTENV("SCRIPT_FILENAME", NULL);
1.1       misho    1351:                                        SG(sapi_headers).http_response_code = 404;
                   1352:                                }
                   1353:                                if (!SG(request_info).request_uri) {
                   1354:                                        if (!orig_script_name ||
                   1355:                                                strcmp(orig_script_name, env_script_name) != 0) {
                   1356:                                                if (orig_script_name) {
1.1.1.2 ! misho    1357:                                                        CGI_PUTENV("ORIG_SCRIPT_NAME", orig_script_name);
1.1       misho    1358:                                                }
1.1.1.2 ! misho    1359:                                                SG(request_info).request_uri = CGI_PUTENV("SCRIPT_NAME", env_script_name);
1.1       misho    1360:                                        } else {
                   1361:                                                SG(request_info).request_uri = orig_script_name;
                   1362:                                        }
                   1363:                                }
                   1364:                                if (pt) {
                   1365:                                        efree(pt);
                   1366:                                }
                   1367:                        } else {
                   1368:                                /* make sure path_info/translated are empty */
                   1369:                                if (!orig_script_filename ||
                   1370:                                        (script_path_translated != orig_script_filename &&
                   1371:                                        strcmp(script_path_translated, orig_script_filename) != 0)) {
                   1372:                                        if (orig_script_filename) {
1.1.1.2 ! misho    1373:                                                CGI_PUTENV("ORIG_SCRIPT_FILENAME", orig_script_filename);
1.1       misho    1374:                                        }
1.1.1.2 ! misho    1375:                                        script_path_translated = CGI_PUTENV("SCRIPT_FILENAME", script_path_translated);
1.1       misho    1376:                                }
                   1377:                                if (env_redirect_url) {
                   1378:                                        if (orig_path_info) {
1.1.1.2 ! misho    1379:                                                CGI_PUTENV("ORIG_PATH_INFO", orig_path_info);
        !          1380:                                                CGI_PUTENV("PATH_INFO", NULL);
1.1       misho    1381:                                        }
                   1382:                                        if (orig_path_translated) {
1.1.1.2 ! misho    1383:                                                CGI_PUTENV("ORIG_PATH_TRANSLATED", orig_path_translated);
        !          1384:                                                CGI_PUTENV("PATH_TRANSLATED", NULL);
1.1       misho    1385:                                        }
                   1386:                                }
                   1387:                                if (env_script_name != orig_script_name) {
                   1388:                                        if (orig_script_name) {
1.1.1.2 ! misho    1389:                                                CGI_PUTENV("ORIG_SCRIPT_NAME", orig_script_name);
1.1       misho    1390:                                        }
1.1.1.2 ! misho    1391:                                        SG(request_info).request_uri = CGI_PUTENV("SCRIPT_NAME", env_script_name);
1.1       misho    1392:                                } else {
                   1393:                                        SG(request_info).request_uri = env_script_name;
                   1394:                                }
                   1395:                                free(real_path);
                   1396:                        }
                   1397:                } else {
                   1398:                        /* pre 4.3 behaviour, shouldn't be used but provides BC */
                   1399:                        if (env_path_info) {
                   1400:                                SG(request_info).request_uri = env_path_info;
                   1401:                        } else {
                   1402:                                SG(request_info).request_uri = env_script_name;
                   1403:                        }
                   1404:                        if (!CGIG(discard_path) && env_path_translated) {
                   1405:                                script_path_translated = env_path_translated;
                   1406:                        }
                   1407:                }
                   1408: 
                   1409:                if (is_valid_path(script_path_translated)) {
                   1410:                        SG(request_info).path_translated = estrdup(script_path_translated);
                   1411:                }
                   1412: 
1.1.1.2 ! misho    1413:                SG(request_info).request_method = CGI_GETENV("REQUEST_METHOD");
1.1       misho    1414:                /* FIXME - Work out proto_num here */
1.1.1.2 ! misho    1415:                SG(request_info).query_string = CGI_GETENV("QUERY_STRING");
1.1       misho    1416:                SG(request_info).content_type = (content_type ? content_type : "" );
                   1417:                SG(request_info).content_length = (content_length ? atol(content_length) : 0);
                   1418: 
                   1419:                /* The CGI RFC allows servers to pass on unvalidated Authorization data */
1.1.1.2 ! misho    1420:                auth = CGI_GETENV("HTTP_AUTHORIZATION");
1.1       misho    1421:                php_handle_auth_data(auth TSRMLS_CC);
                   1422:        }
                   1423: }
                   1424: /* }}} */
                   1425: 
                   1426: #ifndef PHP_WIN32
                   1427: /**
                   1428:  * Clean up child processes upon exit
                   1429:  */
                   1430: void fastcgi_cleanup(int signal)
                   1431: {
                   1432: #ifdef DEBUG_FASTCGI
                   1433:        fprintf(stderr, "FastCGI shutdown, pid %d\n", getpid());
                   1434: #endif
                   1435: 
                   1436:        sigaction(SIGTERM, &old_term, 0);
                   1437: 
                   1438:        /* Kill all the processes in our process group */
                   1439:        kill(-pgroup, SIGTERM);
                   1440: 
                   1441:        if (parent && parent_waiting) {
                   1442:                exit_signal = 1;
                   1443:        } else {
                   1444:                exit(0);
                   1445:        }
                   1446: }
                   1447: #endif
                   1448: 
                   1449: PHP_INI_BEGIN()
                   1450:        STD_PHP_INI_ENTRY("cgi.rfc2616_headers",     "0",  PHP_INI_ALL,    OnUpdateBool,   rfc2616_headers, php_cgi_globals_struct, php_cgi_globals)
                   1451:        STD_PHP_INI_ENTRY("cgi.nph",                 "0",  PHP_INI_ALL,    OnUpdateBool,   nph, php_cgi_globals_struct, php_cgi_globals)
                   1452:        STD_PHP_INI_ENTRY("cgi.check_shebang_line",  "1",  PHP_INI_SYSTEM, OnUpdateBool,   check_shebang_line, php_cgi_globals_struct, php_cgi_globals)
                   1453:        STD_PHP_INI_ENTRY("cgi.force_redirect",      "1",  PHP_INI_SYSTEM, OnUpdateBool,   force_redirect, php_cgi_globals_struct, php_cgi_globals)
                   1454:        STD_PHP_INI_ENTRY("cgi.redirect_status_env", NULL, PHP_INI_SYSTEM, OnUpdateString, redirect_status_env, php_cgi_globals_struct, php_cgi_globals)
                   1455:        STD_PHP_INI_ENTRY("cgi.fix_pathinfo",        "1",  PHP_INI_SYSTEM, OnUpdateBool,   fix_pathinfo, php_cgi_globals_struct, php_cgi_globals)
                   1456:        STD_PHP_INI_ENTRY("cgi.discard_path",        "0",  PHP_INI_SYSTEM, OnUpdateBool,   discard_path, php_cgi_globals_struct, php_cgi_globals)
                   1457:        STD_PHP_INI_ENTRY("fastcgi.logging",         "1",  PHP_INI_SYSTEM, OnUpdateBool,   fcgi_logging, php_cgi_globals_struct, php_cgi_globals)
                   1458: #ifdef PHP_WIN32
                   1459:        STD_PHP_INI_ENTRY("fastcgi.impersonate",     "0",  PHP_INI_SYSTEM, OnUpdateBool,   impersonate, php_cgi_globals_struct, php_cgi_globals)
                   1460: #endif
                   1461: PHP_INI_END()
                   1462: 
                   1463: /* {{{ php_cgi_globals_ctor
                   1464:  */
                   1465: static void php_cgi_globals_ctor(php_cgi_globals_struct *php_cgi_globals TSRMLS_DC)
                   1466: {
                   1467:        php_cgi_globals->rfc2616_headers = 0;
                   1468:        php_cgi_globals->nph = 0;
                   1469:        php_cgi_globals->check_shebang_line = 1;
                   1470:        php_cgi_globals->force_redirect = 1;
                   1471:        php_cgi_globals->redirect_status_env = NULL;
                   1472:        php_cgi_globals->fix_pathinfo = 1;
                   1473:        php_cgi_globals->discard_path = 0;
                   1474:        php_cgi_globals->fcgi_logging = 1;
                   1475: #ifdef PHP_WIN32
                   1476:        php_cgi_globals->impersonate = 0;
                   1477: #endif
                   1478:        zend_hash_init(&php_cgi_globals->user_config_cache, 0, NULL, (dtor_func_t) user_config_cache_entry_dtor, 1);
                   1479: }
                   1480: /* }}} */
                   1481: 
                   1482: /* {{{ PHP_MINIT_FUNCTION
                   1483:  */
                   1484: static PHP_MINIT_FUNCTION(cgi)
                   1485: {
                   1486: #ifdef ZTS
                   1487:        ts_allocate_id(&php_cgi_globals_id, sizeof(php_cgi_globals_struct), (ts_allocate_ctor) php_cgi_globals_ctor, NULL);
                   1488: #else
                   1489:        php_cgi_globals_ctor(&php_cgi_globals TSRMLS_CC);
                   1490: #endif
                   1491:        REGISTER_INI_ENTRIES();
                   1492:        return SUCCESS;
                   1493: }
                   1494: /* }}} */
                   1495: 
                   1496: /* {{{ PHP_MSHUTDOWN_FUNCTION
                   1497:  */
                   1498: static PHP_MSHUTDOWN_FUNCTION(cgi)
                   1499: {
                   1500:        zend_hash_destroy(&CGIG(user_config_cache));
                   1501: 
                   1502:        UNREGISTER_INI_ENTRIES();
                   1503:        return SUCCESS;
                   1504: }
                   1505: /* }}} */
                   1506: 
                   1507: /* {{{ PHP_MINFO_FUNCTION
                   1508:  */
                   1509: static PHP_MINFO_FUNCTION(cgi)
                   1510: {
                   1511:        DISPLAY_INI_ENTRIES();
                   1512: }
                   1513: /* }}} */
                   1514: 
1.1.1.2 ! misho    1515: PHP_FUNCTION(apache_child_terminate) /* {{{ */
        !          1516: {
        !          1517:        if (ZEND_NUM_ARGS() > 0) {
        !          1518:                WRONG_PARAM_COUNT;
        !          1519:        }
        !          1520:        if (fcgi_is_fastcgi()) {
        !          1521:                fcgi_terminate();
        !          1522:        }
        !          1523: }
        !          1524: /* }}} */
        !          1525: 
        !          1526: static void add_request_header(char *var, unsigned int var_len, char *val, unsigned int val_len, void *arg TSRMLS_DC) /* {{{ */
        !          1527: {
        !          1528:        zval *return_value = (zval*)arg;
        !          1529:        char *str = NULL;
        !          1530:        char *p;
        !          1531:        ALLOCA_FLAG(use_heap)
        !          1532: 
        !          1533:        if (var_len > 5 &&
        !          1534:            var[0] == 'H' &&
        !          1535:            var[1] == 'T' &&
        !          1536:            var[2] == 'T' &&
        !          1537:            var[3] == 'P' &&
        !          1538:            var[4] == '_') {
        !          1539: 
        !          1540:                var_len -= 5;
        !          1541:                p = var + 5;
        !          1542:                var = str = do_alloca(var_len + 1, use_heap);
        !          1543:                *str++ = *p++;
        !          1544:                while (*p) {
        !          1545:                        if (*p == '_') {
        !          1546:                                *str++ = '-';
        !          1547:                                p++;
        !          1548:                                if (*p) {
        !          1549:                                        *str++ = *p++;
        !          1550:                                }
        !          1551:                        } else if (*p >= 'A' && *p <= 'Z') {
        !          1552:                                *str++ = (*p++ - 'A' + 'a');
        !          1553:                        } else {
        !          1554:                                *str++ = *p++;
        !          1555:                        }
        !          1556:                }
        !          1557:                *str = 0;
        !          1558:        } else if (var_len == sizeof("CONTENT_TYPE")-1 &&
        !          1559:                   memcmp(var, "CONTENT_TYPE", sizeof("CONTENT_TYPE")-1) == 0) {
        !          1560:                var = "Content-Type";
        !          1561:        } else if (var_len == sizeof("CONTENT_LENGTH")-1 &&
        !          1562:                   memcmp(var, "CONTENT_LENGTH", sizeof("CONTENT_LENGTH")-1) == 0) {
        !          1563:                var = "Content-Length";
        !          1564:        } else {
        !          1565:                return;
        !          1566:        }
        !          1567:        add_assoc_stringl_ex(return_value, var, var_len+1, val, val_len, 1);
        !          1568:        if (str) {
        !          1569:                free_alloca(var, use_heap);
        !          1570:        }
        !          1571: }
        !          1572: /* }}} */
        !          1573: 
        !          1574: PHP_FUNCTION(apache_request_headers) /* {{{ */
        !          1575: {
        !          1576:        if (ZEND_NUM_ARGS() > 0) {
        !          1577:                WRONG_PARAM_COUNT;
        !          1578:        }
        !          1579:        array_init(return_value);
        !          1580:        if (fcgi_is_fastcgi()) {
        !          1581:                fcgi_request *request = (fcgi_request*) SG(server_context);
        !          1582: 
        !          1583:                fcgi_loadenv(request, add_request_header, return_value TSRMLS_CC);
        !          1584:        } else {
        !          1585:                char buf[128];
        !          1586:                char **env, *p, *q, *var, *val, *t = buf;
        !          1587:                size_t alloc_size = sizeof(buf);
        !          1588:                unsigned long var_len;
        !          1589: 
        !          1590:                for (env = environ; env != NULL && *env != NULL; env++) {
        !          1591:                        val = strchr(*env, '=');
        !          1592:                        if (!val) {                             /* malformed entry? */
        !          1593:                                continue;
        !          1594:                        }
        !          1595:                        var_len = val - *env;
        !          1596:                        if (var_len >= alloc_size) {
        !          1597:                                alloc_size = var_len + 64;
        !          1598:                                t = (t == buf ? emalloc(alloc_size): erealloc(t, alloc_size));
        !          1599:                        }
        !          1600:                        var = *env;
        !          1601:                        if (var_len > 5 &&
        !          1602:                            var[0] == 'H' &&
        !          1603:                            var[1] == 'T' &&
        !          1604:                            var[2] == 'T' &&
        !          1605:                            var[3] == 'P' &&
        !          1606:                            var[4] == '_') {
        !          1607: 
        !          1608:                                var_len -= 5;
        !          1609: 
        !          1610:                                if (var_len >= alloc_size) {
        !          1611:                                        alloc_size = var_len + 64;
        !          1612:                                        t = (t == buf ? emalloc(alloc_size): erealloc(t, alloc_size));
        !          1613:                                }
        !          1614:                                p = var + 5;
        !          1615: 
        !          1616:                                var = q = t;
        !          1617:                                // First char keep uppercase
        !          1618:                                *q++ = *p++;
        !          1619:                                while (*p) {
        !          1620:                                        if (*p == '=') {
        !          1621:                                                // End of name
        !          1622:                                                break;
        !          1623:                                        } else if (*p == '_') {
        !          1624:                                                *q++ = '-';
        !          1625:                                                p++;
        !          1626:                                                // First char after - keep uppercase
        !          1627:                                                if (*p && *p!='=') {
        !          1628:                                                        *q++ = *p++;
        !          1629:                                                }
        !          1630:                                        } else if (*p >= 'A' && *p <= 'Z') {
        !          1631:                                                // lowercase
        !          1632:                                                *q++ = (*p++ - 'A' + 'a');
        !          1633:                                        } else {
        !          1634:                                                *q++ = *p++;
        !          1635:                                        }
        !          1636:                                }
        !          1637:                                *q = 0;
        !          1638:                        } else if (var_len == sizeof("CONTENT_TYPE")-1 &&
        !          1639:                                   memcmp(var, "CONTENT_TYPE", sizeof("CONTENT_TYPE")-1) == 0) {
        !          1640:                                var = "Content-Type";
        !          1641:                        } else if (var_len == sizeof("CONTENT_LENGTH")-1 &&
        !          1642:                                   memcmp(var, "CONTENT_LENGTH", sizeof("CONTENT_LENGTH")-1) == 0) {
        !          1643:                                var = "Content-Length";
        !          1644:                        } else {
        !          1645:                                continue;
        !          1646:                        }
        !          1647:                        val++;
        !          1648:                        add_assoc_string_ex(return_value, var, var_len+1, val, 1);
        !          1649:                }
        !          1650:                if (t != buf && t != NULL) {
        !          1651:                        efree(t);
        !          1652:                }
        !          1653:        }
        !          1654: }
        !          1655: /* }}} */
        !          1656: 
        !          1657: static void add_response_header(sapi_header_struct *h, zval *return_value TSRMLS_DC) /* {{{ */
        !          1658: {
        !          1659:        char *s, *p;
        !          1660:        int  len;
        !          1661:        ALLOCA_FLAG(use_heap)
        !          1662: 
        !          1663:        if (h->header_len > 0) {
        !          1664:                p = strchr(h->header, ':');
        !          1665:                len = p - h->header;
        !          1666:                if (p && (len > 0)) {
        !          1667:                        while (len > 0 && (h->header[len-1] == ' ' || h->header[len-1] == '\t')) {
        !          1668:                                len--;
        !          1669:                        }
        !          1670:                        if (len) {
        !          1671:                                s = do_alloca(len + 1, use_heap);
        !          1672:                                memcpy(s, h->header, len);
        !          1673:                                s[len] = 0;
        !          1674:                                do {
        !          1675:                                        p++;
        !          1676:                                } while (*p == ' ' || *p == '\t');
        !          1677:                                add_assoc_stringl_ex(return_value, s, len+1, p, h->header_len - (p - h->header), 1);
        !          1678:                                free_alloca(s, use_heap);
        !          1679:                        }
        !          1680:                }
        !          1681:        }
        !          1682: }
        !          1683: /* }}} */
        !          1684: 
        !          1685: PHP_FUNCTION(apache_response_headers) /* {{{ */
        !          1686: {
        !          1687:        if (ZEND_NUM_ARGS() > 0) {
        !          1688:                WRONG_PARAM_COUNT;
        !          1689:        }
        !          1690: 
        !          1691:        if (!&SG(sapi_headers).headers) {
        !          1692:                RETURN_FALSE;
        !          1693:        }
        !          1694:        array_init(return_value);
        !          1695:        zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t)add_response_header, return_value TSRMLS_CC);
        !          1696: }
        !          1697: /* }}} */
        !          1698: 
        !          1699: ZEND_BEGIN_ARG_INFO(arginfo_no_args, 0)
        !          1700: ZEND_END_ARG_INFO()
        !          1701: 
        !          1702: const zend_function_entry cgi_functions[] = {
        !          1703:        PHP_FE(apache_child_terminate, arginfo_no_args)
        !          1704:        PHP_FE(apache_request_headers, arginfo_no_args)
        !          1705:        PHP_FE(apache_response_headers, arginfo_no_args)
        !          1706:        PHP_FALIAS(getallheaders, apache_request_headers, arginfo_no_args)
        !          1707:        {NULL, NULL, NULL}
        !          1708: };
        !          1709: 
1.1       misho    1710: static zend_module_entry cgi_module_entry = {
                   1711:        STANDARD_MODULE_HEADER,
                   1712:        "cgi-fcgi",
1.1.1.2 ! misho    1713:        cgi_functions,
1.1       misho    1714:        PHP_MINIT(cgi),
                   1715:        PHP_MSHUTDOWN(cgi),
                   1716:        NULL,
                   1717:        NULL,
                   1718:        PHP_MINFO(cgi),
                   1719:        NO_VERSION_YET,
                   1720:        STANDARD_MODULE_PROPERTIES
                   1721: };
                   1722: 
                   1723: /* {{{ main
                   1724:  */
                   1725: int main(int argc, char *argv[])
                   1726: {
                   1727:        int free_query_string = 0;
                   1728:        int exit_status = SUCCESS;
                   1729:        int cgi = 0, c, i, len;
                   1730:        zend_file_handle file_handle;
                   1731:        char *s;
                   1732: 
                   1733:        /* temporary locals */
                   1734:        int behavior = PHP_MODE_STANDARD;
                   1735:        int no_headers = 0;
                   1736:        int orig_optind = php_optind;
                   1737:        char *orig_optarg = php_optarg;
                   1738:        char *script_file = NULL;
                   1739:        int ini_entries_len = 0;
                   1740:        /* end of temporary locals */
                   1741: 
                   1742: #ifdef ZTS
                   1743:        void ***tsrm_ls;
                   1744: #endif
                   1745: 
                   1746:        int max_requests = 500;
                   1747:        int requests = 0;
1.1.1.2 ! misho    1748:        int fastcgi;
1.1       misho    1749:        char *bindpath = NULL;
                   1750:        int fcgi_fd = 0;
1.1.1.2 ! misho    1751:        fcgi_request *request = NULL;
1.1       misho    1752:        int repeats = 1;
                   1753:        int benchmark = 0;
                   1754: #if HAVE_GETTIMEOFDAY
                   1755:        struct timeval start, end;
                   1756: #else
                   1757:        time_t start, end;
                   1758: #endif
                   1759: #ifndef PHP_WIN32
                   1760:        int status = 0;
                   1761: #endif
1.1.1.2 ! misho    1762:        char *query_string;
        !          1763:        char *decoded_query_string;
        !          1764:        int skip_getopt = 0;
1.1       misho    1765: 
                   1766: #if 0 && defined(PHP_DEBUG)
                   1767:        /* IIS is always making things more difficult.  This allows
                   1768:         * us to stop PHP and attach a debugger before much gets started */
                   1769:        {
                   1770:                char szMessage [256];
                   1771:                wsprintf (szMessage, "Please attach a debugger to the process 0x%X [%d] (%s) and click OK", GetCurrentProcessId(), GetCurrentProcessId(), argv[0]);
                   1772:                MessageBox(NULL, szMessage, "CGI Debug Time!", MB_OK|MB_SERVICE_NOTIFICATION);
                   1773:        }
                   1774: #endif
                   1775: 
                   1776: #ifdef HAVE_SIGNAL_H
                   1777: #if defined(SIGPIPE) && defined(SIG_IGN)
                   1778:        signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE in standalone mode so
                   1779:                                                                that sockets created via fsockopen()
                   1780:                                                                don't kill PHP if the remote site
                   1781:                                                                closes it.  in apache|apxs mode apache
                   1782:                                                                does that for us!  thies@thieso.net
                   1783:                                                                20000419 */
                   1784: #endif
                   1785: #endif
                   1786: 
                   1787: #ifdef ZTS
                   1788:        tsrm_startup(1, 1, 0, NULL);
                   1789:        tsrm_ls = ts_resource(0);
                   1790: #endif
                   1791: 
                   1792:        sapi_startup(&cgi_sapi_module);
1.1.1.2 ! misho    1793:        fastcgi = fcgi_is_fastcgi();
1.1       misho    1794:        cgi_sapi_module.php_ini_path_override = NULL;
                   1795: 
                   1796: #ifdef PHP_WIN32
                   1797:        _fmode = _O_BINARY; /* sets default for file streams to binary */
                   1798:        setmode(_fileno(stdin),  O_BINARY);     /* make the stdio mode be binary */
                   1799:        setmode(_fileno(stdout), O_BINARY);     /* make the stdio mode be binary */
                   1800:        setmode(_fileno(stderr), O_BINARY);     /* make the stdio mode be binary */
                   1801: #endif
                   1802: 
                   1803:        if (!fastcgi) {
                   1804:                /* Make sure we detect we are a cgi - a bit redundancy here,
                   1805:                 * but the default case is that we have to check only the first one. */
                   1806:                if (getenv("SERVER_SOFTWARE") ||
                   1807:                        getenv("SERVER_NAME") ||
                   1808:                        getenv("GATEWAY_INTERFACE") ||
                   1809:                        getenv("REQUEST_METHOD")
                   1810:                ) {
                   1811:                        cgi = 1;
                   1812:                }
                   1813:        }
                   1814: 
1.1.1.2 ! misho    1815:        if((query_string = getenv("QUERY_STRING")) != NULL && strchr(query_string, '=') == NULL) {
        !          1816:                /* we've got query string that has no = - apache CGI will pass it to command line */
        !          1817:                unsigned char *p;
        !          1818:                decoded_query_string = strdup(query_string);
        !          1819:                php_url_decode(decoded_query_string, strlen(decoded_query_string));
        !          1820:                for (p = decoded_query_string; *p &&  *p <= ' '; p++) {
        !          1821:                        /* skip all leading spaces */
        !          1822:                }
        !          1823:                if(*p == '-') {
        !          1824:                        skip_getopt = 1;
        !          1825:                }
        !          1826:                free(decoded_query_string);
        !          1827:        }
        !          1828: 
        !          1829:        while (!skip_getopt && (c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
1.1       misho    1830:                switch (c) {
                   1831:                        case 'c':
                   1832:                                if (cgi_sapi_module.php_ini_path_override) {
                   1833:                                        free(cgi_sapi_module.php_ini_path_override);
                   1834:                                }
                   1835:                                cgi_sapi_module.php_ini_path_override = strdup(php_optarg);
                   1836:                                break;
                   1837:                        case 'n':
                   1838:                                cgi_sapi_module.php_ini_ignore = 1;
                   1839:                                break;
                   1840:                        case 'd': {
                   1841:                                /* define ini entries on command line */
                   1842:                                int len = strlen(php_optarg);
                   1843:                                char *val;
                   1844: 
                   1845:                                if ((val = strchr(php_optarg, '='))) {
                   1846:                                        val++;
                   1847:                                        if (!isalnum(*val) && *val != '"' && *val != '\'' && *val != '\0') {
                   1848:                                                cgi_sapi_module.ini_entries = realloc(cgi_sapi_module.ini_entries, ini_entries_len + len + sizeof("\"\"\n\0"));
                   1849:                                                memcpy(cgi_sapi_module.ini_entries + ini_entries_len, php_optarg, (val - php_optarg));
                   1850:                                                ini_entries_len += (val - php_optarg);
                   1851:                                                memcpy(cgi_sapi_module.ini_entries + ini_entries_len, "\"", 1);
                   1852:                                                ini_entries_len++;
                   1853:                                                memcpy(cgi_sapi_module.ini_entries + ini_entries_len, val, len - (val - php_optarg));
                   1854:                                                ini_entries_len += len - (val - php_optarg);
                   1855:                                                memcpy(cgi_sapi_module.ini_entries + ini_entries_len, "\"\n\0", sizeof("\"\n\0"));
                   1856:                                                ini_entries_len += sizeof("\n\0\"") - 2;
                   1857:                                        } else {
                   1858:                                                cgi_sapi_module.ini_entries = realloc(cgi_sapi_module.ini_entries, ini_entries_len + len + sizeof("\n\0"));
                   1859:                                                memcpy(cgi_sapi_module.ini_entries + ini_entries_len, php_optarg, len);
                   1860:                                                memcpy(cgi_sapi_module.ini_entries + ini_entries_len + len, "\n\0", sizeof("\n\0"));
                   1861:                                                ini_entries_len += len + sizeof("\n\0") - 2;
                   1862:                                        }
                   1863:                                } else {
                   1864:                                        cgi_sapi_module.ini_entries = realloc(cgi_sapi_module.ini_entries, ini_entries_len + len + sizeof("=1\n\0"));
                   1865:                                        memcpy(cgi_sapi_module.ini_entries + ini_entries_len, php_optarg, len);
                   1866:                                        memcpy(cgi_sapi_module.ini_entries + ini_entries_len + len, "=1\n\0", sizeof("=1\n\0"));
                   1867:                                        ini_entries_len += len + sizeof("=1\n\0") - 2;
                   1868:                                }
                   1869:                                break;
                   1870:                        }
                   1871:                        /* if we're started on command line, check to see if
                   1872:                         * we are being started as an 'external' fastcgi
                   1873:                         * server by accepting a bindpath parameter. */
                   1874:                        case 'b':
                   1875:                                if (!fastcgi) {
                   1876:                                        bindpath = strdup(php_optarg);
                   1877:                                }
                   1878:                                break;
                   1879:                        case 's': /* generate highlighted HTML from source */
                   1880:                                behavior = PHP_MODE_HIGHLIGHT;
                   1881:                                break;
                   1882:                }
                   1883:        }
                   1884:        php_optind = orig_optind;
                   1885:        php_optarg = orig_optarg;
                   1886: 
1.1.1.2 ! misho    1887:        if (fastcgi || bindpath) {
        !          1888:                /* Override SAPI callbacks */
        !          1889:                cgi_sapi_module.ub_write     = sapi_fcgi_ub_write;
        !          1890:                cgi_sapi_module.flush        = sapi_fcgi_flush;
        !          1891:                cgi_sapi_module.read_post    = sapi_fcgi_read_post;
        !          1892:                cgi_sapi_module.getenv       = sapi_fcgi_getenv;
        !          1893:                cgi_sapi_module.read_cookies = sapi_fcgi_read_cookies;
        !          1894:        }
        !          1895: 
1.1       misho    1896: #ifdef ZTS
                   1897:        SG(request_info).path_translated = NULL;
                   1898: #endif
                   1899: 
                   1900:        cgi_sapi_module.executable_location = argv[0];
                   1901:        if (!cgi && !fastcgi && !bindpath) {
                   1902:                cgi_sapi_module.additional_functions = additional_functions;
                   1903:        }
                   1904: 
                   1905:        /* startup after we get the above ini override se we get things right */
                   1906:        if (cgi_sapi_module.startup(&cgi_sapi_module) == FAILURE) {
                   1907: #ifdef ZTS
                   1908:                tsrm_shutdown();
                   1909: #endif
                   1910:                return FAILURE;
                   1911:        }
                   1912: 
                   1913:        /* check force_cgi after startup, so we have proper output */
                   1914:        if (cgi && CGIG(force_redirect)) {
                   1915:                /* Apache will generate REDIRECT_STATUS,
                   1916:                 * Netscape and redirect.so will generate HTTP_REDIRECT_STATUS.
                   1917:                 * redirect.so and installation instructions available from
                   1918:                 * http://www.koehntopp.de/php.
                   1919:                 *   -- kk@netuse.de
                   1920:                 */
                   1921:                if (!getenv("REDIRECT_STATUS") &&
                   1922:                        !getenv ("HTTP_REDIRECT_STATUS") &&
                   1923:                        /* this is to allow a different env var to be configured
                   1924:                         * in case some server does something different than above */
                   1925:                        (!CGIG(redirect_status_env) || !getenv(CGIG(redirect_status_env)))
                   1926:                ) {
                   1927:                        zend_try {
                   1928:                                SG(sapi_headers).http_response_code = 400;
                   1929:                                PUTS("<b>Security Alert!</b> The PHP CGI cannot be accessed directly.\n\n\
                   1930: <p>This PHP CGI binary was compiled with force-cgi-redirect enabled.  This\n\
                   1931: means that a page will only be served up if the REDIRECT_STATUS CGI variable is\n\
                   1932: set, e.g. via an Apache Action directive.</p>\n\
                   1933: <p>For more information as to <i>why</i> this behaviour exists, see the <a href=\"http://php.net/security.cgi-bin\">\
                   1934: manual page for CGI security</a>.</p>\n\
                   1935: <p>For more information about changing this behaviour or re-enabling this webserver,\n\
                   1936: consult the installation file that came with this distribution, or visit \n\
                   1937: <a href=\"http://php.net/install.windows\">the manual page</a>.</p>\n");
                   1938:                        } zend_catch {
                   1939:                        } zend_end_try();
                   1940: #if defined(ZTS) && !defined(PHP_DEBUG)
                   1941:                        /* XXX we're crashing here in msvc6 debug builds at
                   1942:                         * php_message_handler_for_zend:839 because
                   1943:                         * SG(request_info).path_translated is an invalid pointer.
                   1944:                         * It still happens even though I set it to null, so something
                   1945:                         * weird is going on.
                   1946:                         */
                   1947:                        tsrm_shutdown();
                   1948: #endif
                   1949:                        return FAILURE;
                   1950:                }
                   1951:        }
                   1952: 
                   1953:        if (bindpath) {
                   1954:                fcgi_fd = fcgi_listen(bindpath, 128);
                   1955:                if (fcgi_fd < 0) {
                   1956:                        fprintf(stderr, "Couldn't create FastCGI listen socket on port %s\n", bindpath);
                   1957: #ifdef ZTS
                   1958:                        tsrm_shutdown();
                   1959: #endif
                   1960:                        return FAILURE;
                   1961:                }
                   1962:                fastcgi = fcgi_is_fastcgi();
                   1963:        }
                   1964:        if (fastcgi) {
                   1965:                /* How many times to run PHP scripts before dying */
                   1966:                if (getenv("PHP_FCGI_MAX_REQUESTS")) {
                   1967:                        max_requests = atoi(getenv("PHP_FCGI_MAX_REQUESTS"));
                   1968:                        if (max_requests < 0) {
                   1969:                                fprintf(stderr, "PHP_FCGI_MAX_REQUESTS is not valid\n");
                   1970:                                return FAILURE;
                   1971:                        }
                   1972:                }
                   1973: 
                   1974:                /* make php call us to get _ENV vars */
                   1975:                php_php_import_environment_variables = php_import_environment_variables;
                   1976:                php_import_environment_variables = cgi_php_import_environment_variables;
                   1977: 
                   1978:                /* library is already initialized, now init our request */
1.1.1.2 ! misho    1979:                request = fcgi_init_request(fcgi_fd);
1.1       misho    1980: 
                   1981: #ifndef PHP_WIN32
                   1982:        /* Pre-fork, if required */
                   1983:        if (getenv("PHP_FCGI_CHILDREN")) {
                   1984:                char * children_str = getenv("PHP_FCGI_CHILDREN");
                   1985:                children = atoi(children_str);
                   1986:                if (children < 0) {
                   1987:                        fprintf(stderr, "PHP_FCGI_CHILDREN is not valid\n");
                   1988:                        return FAILURE;
                   1989:                }
                   1990:                fcgi_set_mgmt_var("FCGI_MAX_CONNS", sizeof("FCGI_MAX_CONNS")-1, children_str, strlen(children_str));
                   1991:                /* This is the number of concurrent requests, equals FCGI_MAX_CONNS */
                   1992:                fcgi_set_mgmt_var("FCGI_MAX_REQS",  sizeof("FCGI_MAX_REQS")-1,  children_str, strlen(children_str));
                   1993:        } else {
                   1994:                fcgi_set_mgmt_var("FCGI_MAX_CONNS", sizeof("FCGI_MAX_CONNS")-1, "1", sizeof("1")-1);
                   1995:                fcgi_set_mgmt_var("FCGI_MAX_REQS",  sizeof("FCGI_MAX_REQS")-1,  "1", sizeof("1")-1);
                   1996:        }
                   1997: 
                   1998:        if (children) {
                   1999:                int running = 0;
                   2000:                pid_t pid;
                   2001: 
                   2002:                /* Create a process group for ourself & children */
                   2003:                setsid();
                   2004:                pgroup = getpgrp();
                   2005: #ifdef DEBUG_FASTCGI
                   2006:                fprintf(stderr, "Process group %d\n", pgroup);
                   2007: #endif
                   2008: 
                   2009:                /* Set up handler to kill children upon exit */
                   2010:                act.sa_flags = 0;
                   2011:                act.sa_handler = fastcgi_cleanup;
                   2012:                if (sigaction(SIGTERM, &act, &old_term) ||
                   2013:                        sigaction(SIGINT,  &act, &old_int)  ||
                   2014:                        sigaction(SIGQUIT, &act, &old_quit)
                   2015:                ) {
                   2016:                        perror("Can't set signals");
                   2017:                        exit(1);
                   2018:                }
                   2019: 
                   2020:                if (fcgi_in_shutdown()) {
                   2021:                        goto parent_out;
                   2022:                }
                   2023: 
                   2024:                while (parent) {
                   2025:                        do {
                   2026: #ifdef DEBUG_FASTCGI
                   2027:                                fprintf(stderr, "Forking, %d running\n", running);
                   2028: #endif
                   2029:                                pid = fork();
                   2030:                                switch (pid) {
                   2031:                                case 0:
                   2032:                                        /* One of the children.
                   2033:                                         * Make sure we don't go round the
                   2034:                                         * fork loop any more
                   2035:                                         */
                   2036:                                        parent = 0;
                   2037: 
                   2038:                                        /* don't catch our signals */
                   2039:                                        sigaction(SIGTERM, &old_term, 0);
                   2040:                                        sigaction(SIGQUIT, &old_quit, 0);
                   2041:                                        sigaction(SIGINT,  &old_int,  0);
                   2042:                                        break;
                   2043:                                case -1:
                   2044:                                        perror("php (pre-forking)");
                   2045:                                        exit(1);
                   2046:                                        break;
                   2047:                                default:
                   2048:                                        /* Fine */
                   2049:                                        running++;
                   2050:                                        break;
                   2051:                                }
                   2052:                        } while (parent && (running < children));
                   2053: 
                   2054:                        if (parent) {
                   2055: #ifdef DEBUG_FASTCGI
                   2056:                                fprintf(stderr, "Wait for kids, pid %d\n", getpid());
                   2057: #endif
                   2058:                                parent_waiting = 1;
                   2059:                                while (1) {
                   2060:                                        if (wait(&status) >= 0) {
                   2061:                                                running--;
                   2062:                                                break;
                   2063:                                        } else if (exit_signal) {
                   2064:                                                break;
                   2065:                                        }
                   2066:                                }
                   2067:                                if (exit_signal) {
                   2068: #if 0
                   2069:                                        while (running > 0) {
                   2070:                                                while (wait(&status) < 0) {
                   2071:                                                }
                   2072:                                                running--;
                   2073:                                        }
                   2074: #endif
                   2075:                                        goto parent_out;
                   2076:                                }
                   2077:                        }
                   2078:                }
                   2079:        } else {
                   2080:                parent = 0;
                   2081:        }
                   2082: 
                   2083: #endif /* WIN32 */
                   2084:        }
                   2085: 
                   2086:        zend_first_try {
1.1.1.2 ! misho    2087:                while (!skip_getopt && (c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 1, 2)) != -1) {
1.1       misho    2088:                        switch (c) {
                   2089:                                case 'T':
                   2090:                                        benchmark = 1;
                   2091:                                        repeats = atoi(php_optarg);
                   2092: #ifdef HAVE_GETTIMEOFDAY
                   2093:                                        gettimeofday(&start, NULL);
                   2094: #else
                   2095:                                        time(&start);
                   2096: #endif
                   2097:                                        break;
                   2098:                                case 'h':
                   2099:                                case '?':
1.1.1.2 ! misho    2100:                                        if (request) {
        !          2101:                                                fcgi_destroy_request(request);
        !          2102:                                        }
1.1       misho    2103:                                        fcgi_shutdown();
                   2104:                                        no_headers = 1;
                   2105:                                        SG(headers_sent) = 1;
                   2106:                                        php_cgi_usage(argv[0]);
1.1.1.2 ! misho    2107:                                        php_output_end_all(TSRMLS_C);
1.1       misho    2108:                                        exit_status = 0;
                   2109:                                        goto out;
                   2110:                        }
                   2111:                }
                   2112:                php_optind = orig_optind;
                   2113:                php_optarg = orig_optarg;
                   2114: 
                   2115:                /* start of FAST CGI loop */
                   2116:                /* Initialise FastCGI request structure */
                   2117: #ifdef PHP_WIN32
                   2118:                /* attempt to set security impersonation for fastcgi
                   2119:                 * will only happen on NT based OS, others will ignore it. */
                   2120:                if (fastcgi && CGIG(impersonate)) {
                   2121:                        fcgi_impersonate();
                   2122:                }
                   2123: #endif
1.1.1.2 ! misho    2124:                while (!fastcgi || fcgi_accept_request(request) >= 0) {
        !          2125:                        SG(server_context) = fastcgi ? (void *) request : (void *) 1;
        !          2126:                        init_request_info(request TSRMLS_CC);
1.1       misho    2127:                        CG(interactive) = 0;
                   2128: 
                   2129:                        if (!cgi && !fastcgi) {
                   2130:                                while ((c = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
                   2131:                                        switch (c) {
                   2132: 
                   2133:                                                case 'a':       /* interactive mode */
                   2134:                                                        printf("Interactive mode enabled\n\n");
                   2135:                                                        CG(interactive) = 1;
                   2136:                                                        break;
                   2137: 
                   2138:                                                case 'C': /* don't chdir to the script directory */
                   2139:                                                        SG(options) |= SAPI_OPTION_NO_CHDIR;
                   2140:                                                        break;
                   2141: 
                   2142:                                                case 'e': /* enable extended info output */
                   2143:                                                        CG(compiler_options) |= ZEND_COMPILE_EXTENDED_INFO;
                   2144:                                                        break;
                   2145: 
                   2146:                                                case 'f': /* parse file */
                   2147:                                                        if (script_file) {
                   2148:                                                                efree(script_file);
                   2149:                                                        }
                   2150:                                                        script_file = estrdup(php_optarg);
                   2151:                                                        no_headers = 1;
                   2152:                                                        break;
                   2153: 
                   2154:                                                case 'i': /* php info & quit */
                   2155:                                                        if (script_file) {
                   2156:                                                                efree(script_file);
                   2157:                                                        }
                   2158:                                                        if (php_request_startup(TSRMLS_C) == FAILURE) {
                   2159:                                                                SG(server_context) = NULL;
                   2160:                                                                php_module_shutdown(TSRMLS_C);
                   2161:                                                                return FAILURE;
                   2162:                                                        }
                   2163:                                                        if (no_headers) {
                   2164:                                                                SG(headers_sent) = 1;
                   2165:                                                                SG(request_info).no_headers = 1;
                   2166:                                                        }
                   2167:                                                        php_print_info(0xFFFFFFFF TSRMLS_CC);
                   2168:                                                        php_request_shutdown((void *) 0);
                   2169:                                                        fcgi_shutdown();
                   2170:                                                        exit_status = 0;
                   2171:                                                        goto out;
                   2172: 
                   2173:                                                case 'l': /* syntax check mode */
                   2174:                                                        no_headers = 1;
                   2175:                                                        behavior = PHP_MODE_LINT;
                   2176:                                                        break;
                   2177: 
                   2178:                                                case 'm': /* list compiled in modules */
                   2179:                                                        if (script_file) {
                   2180:                                                                efree(script_file);
                   2181:                                                        }
                   2182:                                                        SG(headers_sent) = 1;
                   2183:                                                        php_printf("[PHP Modules]\n");
                   2184:                                                        print_modules(TSRMLS_C);
                   2185:                                                        php_printf("\n[Zend Modules]\n");
                   2186:                                                        print_extensions(TSRMLS_C);
                   2187:                                                        php_printf("\n");
1.1.1.2 ! misho    2188:                                                        php_output_end_all(TSRMLS_C);
1.1       misho    2189:                                                        fcgi_shutdown();
                   2190:                                                        exit_status = 0;
                   2191:                                                        goto out;
                   2192: 
                   2193: #if 0 /* not yet operational, see also below ... */
                   2194:                                                case '': /* generate indented source mode*/
                   2195:                                                        behavior=PHP_MODE_INDENT;
                   2196:                                                        break;
                   2197: #endif
                   2198: 
                   2199:                                                case 'q': /* do not generate HTTP headers */
                   2200:                                                        no_headers = 1;
                   2201:                                                        break;
                   2202: 
                   2203:                                                case 'v': /* show php version & quit */
                   2204:                                                        if (script_file) {
                   2205:                                                                efree(script_file);
                   2206:                                                        }
                   2207:                                                        no_headers = 1;
                   2208:                                                        if (php_request_startup(TSRMLS_C) == FAILURE) {
                   2209:                                                                SG(server_context) = NULL;
                   2210:                                                                php_module_shutdown(TSRMLS_C);
                   2211:                                                                return FAILURE;
                   2212:                                                        }
                   2213:                                                        if (no_headers) {
                   2214:                                                                SG(headers_sent) = 1;
                   2215:                                                                SG(request_info).no_headers = 1;
                   2216:                                                        }
                   2217: #if ZEND_DEBUG
                   2218:                                                        php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2012 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
                   2219: #else
                   2220:                                                        php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2012 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
                   2221: #endif
                   2222:                                                        php_request_shutdown((void *) 0);
                   2223:                                                        fcgi_shutdown();
                   2224:                                                        exit_status = 0;
                   2225:                                                        goto out;
                   2226: 
                   2227:                                                case 'w':
                   2228:                                                        behavior = PHP_MODE_STRIP;
                   2229:                                                        break;
                   2230: 
                   2231:                                                case 'z': /* load extension file */
                   2232:                                                        zend_load_extension(php_optarg);
                   2233:                                                        break;
                   2234: 
                   2235:                                                default:
                   2236:                                                        break;
                   2237:                                        }
                   2238:                                }
                   2239: 
                   2240:                                if (script_file) {
                   2241:                                        /* override path_translated if -f on command line */
                   2242:                                        STR_FREE(SG(request_info).path_translated);
                   2243:                                        SG(request_info).path_translated = script_file;
                   2244:                                        /* before registering argv to module exchange the *new* argv[0] */
                   2245:                                        /* we can achieve this without allocating more memory */
                   2246:                                        SG(request_info).argc = argc - (php_optind - 1);
                   2247:                                        SG(request_info).argv = &argv[php_optind - 1];
                   2248:                                        SG(request_info).argv[0] = script_file;
                   2249:                                } else if (argc > php_optind) {
                   2250:                                        /* file is on command line, but not in -f opt */
                   2251:                                        STR_FREE(SG(request_info).path_translated);
                   2252:                                        SG(request_info).path_translated = estrdup(argv[php_optind]);
                   2253:                                        /* arguments after the file are considered script args */
                   2254:                                        SG(request_info).argc = argc - php_optind;
                   2255:                                        SG(request_info).argv = &argv[php_optind];
                   2256:                                }
                   2257: 
                   2258:                                if (no_headers) {
                   2259:                                        SG(headers_sent) = 1;
                   2260:                                        SG(request_info).no_headers = 1;
                   2261:                                }
                   2262: 
                   2263:                                /* all remaining arguments are part of the query string
                   2264:                                 * this section of code concatenates all remaining arguments
                   2265:                                 * into a single string, seperating args with a &
                   2266:                                 * this allows command lines like:
                   2267:                                 *
                   2268:                                 *  test.php v1=test v2=hello+world!
                   2269:                                 *  test.php "v1=test&v2=hello world!"
                   2270:                                 *  test.php v1=test "v2=hello world!"
                   2271:                                */
                   2272:                                if (!SG(request_info).query_string && argc > php_optind) {
                   2273:                                        int slen = strlen(PG(arg_separator).input);
                   2274:                                        len = 0;
                   2275:                                        for (i = php_optind; i < argc; i++) {
                   2276:                                                if (i < (argc - 1)) {
                   2277:                                                        len += strlen(argv[i]) + slen;
                   2278:                                                } else {
                   2279:                                                        len += strlen(argv[i]);
                   2280:                                                }
                   2281:                                        }
                   2282: 
                   2283:                                        len += 2;
                   2284:                                        s = malloc(len);
                   2285:                                        *s = '\0';                      /* we are pretending it came from the environment  */
                   2286:                                        for (i = php_optind; i < argc; i++) {
                   2287:                                                strlcat(s, argv[i], len);
                   2288:                                                if (i < (argc - 1)) {
                   2289:                                                        strlcat(s, PG(arg_separator).input, len);
                   2290:                                                }
                   2291:                                        }
                   2292:                                        SG(request_info).query_string = s;
                   2293:                                        free_query_string = 1;
                   2294:                                }
                   2295:                        } /* end !cgi && !fastcgi */
                   2296: 
                   2297:                        /*
                   2298:                                we never take stdin if we're (f)cgi, always
                   2299:                                rely on the web server giving us the info
                   2300:                                we need in the environment.
                   2301:                        */
                   2302:                        if (SG(request_info).path_translated || cgi || fastcgi) {
                   2303:                                file_handle.type = ZEND_HANDLE_FILENAME;
                   2304:                                file_handle.filename = SG(request_info).path_translated;
                   2305:                                file_handle.handle.fp = NULL;
                   2306:                        } else {
                   2307:                                file_handle.filename = "-";
                   2308:                                file_handle.type = ZEND_HANDLE_FP;
                   2309:                                file_handle.handle.fp = stdin;
                   2310:                        }
                   2311: 
                   2312:                        file_handle.opened_path = NULL;
                   2313:                        file_handle.free_filename = 0;
                   2314: 
                   2315:                        /* request startup only after we've done all we can to
                   2316:                         * get path_translated */
                   2317:                        if (php_request_startup(TSRMLS_C) == FAILURE) {
                   2318:                                if (fastcgi) {
1.1.1.2 ! misho    2319:                                        fcgi_finish_request(request, 1);
1.1       misho    2320:                                }
                   2321:                                SG(server_context) = NULL;
                   2322:                                php_module_shutdown(TSRMLS_C);
                   2323:                                return FAILURE;
                   2324:                        }
                   2325:                        if (no_headers) {
                   2326:                                SG(headers_sent) = 1;
                   2327:                                SG(request_info).no_headers = 1;
                   2328:                        }
                   2329: 
                   2330:                        /*
                   2331:                                at this point path_translated will be set if:
                   2332:                                1. we are running from shell and got filename was there
                   2333:                                2. we are running as cgi or fastcgi
                   2334:                        */
                   2335:                        if (cgi || fastcgi || SG(request_info).path_translated) {
                   2336:                                if (php_fopen_primary_script(&file_handle TSRMLS_CC) == FAILURE) {
                   2337:                                        zend_try {
                   2338:                                                if (errno == EACCES) {
                   2339:                                                        SG(sapi_headers).http_response_code = 403;
                   2340:                                                        PUTS("Access denied.\n");
                   2341:                                                } else {
                   2342:                                                        SG(sapi_headers).http_response_code = 404;
                   2343:                                                        PUTS("No input file specified.\n");
                   2344:                                                }
                   2345:                                        } zend_catch {
                   2346:                                        } zend_end_try();
                   2347:                                        /* we want to serve more requests if this is fastcgi
                   2348:                                         * so cleanup and continue, request shutdown is
                   2349:                                         * handled later */
                   2350:                                        if (fastcgi) {
                   2351:                                                goto fastcgi_request_done;
                   2352:                                        }
                   2353: 
                   2354:                                        STR_FREE(SG(request_info).path_translated);
                   2355: 
                   2356:                                        if (free_query_string && SG(request_info).query_string) {
                   2357:                                                free(SG(request_info).query_string);
                   2358:                                                SG(request_info).query_string = NULL;
                   2359:                                        }
                   2360: 
                   2361:                                        php_request_shutdown((void *) 0);
                   2362:                                        SG(server_context) = NULL;
                   2363:                                        php_module_shutdown(TSRMLS_C);
                   2364:                                        sapi_shutdown();
                   2365: #ifdef ZTS
                   2366:                                        tsrm_shutdown();
                   2367: #endif
                   2368:                                        return FAILURE;
                   2369:                                }
                   2370:                        }
                   2371: 
1.1.1.2 ! misho    2372:                        if (CGIG(check_shebang_line)) {
1.1       misho    2373:                                /* #!php support */
1.1.1.2 ! misho    2374:                                switch (file_handle.type) {
        !          2375:                                        case ZEND_HANDLE_FD:
        !          2376:                                                if (file_handle.handle.fd < 0) {
        !          2377:                                                        break;
1.1       misho    2378:                                                }
1.1.1.2 ! misho    2379:                                                file_handle.type = ZEND_HANDLE_FP;
        !          2380:                                                file_handle.handle.fp = fdopen(file_handle.handle.fd, "rb");
        !          2381:                                                /* break missing intentionally */
        !          2382:                                        case ZEND_HANDLE_FP:
        !          2383:                                                if (!file_handle.handle.fp ||
        !          2384:                                                    (file_handle.handle.fp == stdin)) {
        !          2385:                                                        break;
        !          2386:                                                }
        !          2387:                                                c = fgetc(file_handle.handle.fp);
        !          2388:                                                if (c == '#') {
        !          2389:                                                        while (c != '\n' && c != '\r' && c != EOF) {
        !          2390:                                                                c = fgetc(file_handle.handle.fp);       /* skip to end of line */
        !          2391:                                                        }
        !          2392:                                                        /* handle situations where line is terminated by \r\n */
        !          2393:                                                        if (c == '\r') {
        !          2394:                                                                if (fgetc(file_handle.handle.fp) != '\n') {
        !          2395:                                                                        long pos = ftell(file_handle.handle.fp);
        !          2396:                                                                        fseek(file_handle.handle.fp, pos - 1, SEEK_SET);
        !          2397:                                                                }
        !          2398:                                                        }
        !          2399:                                                        CG(start_lineno) = 2;
        !          2400:                                                } else {
        !          2401:                                                        rewind(file_handle.handle.fp);
        !          2402:                                                }
        !          2403:                                                break;
        !          2404:                                        case ZEND_HANDLE_STREAM:
        !          2405:                                                c = php_stream_getc((php_stream*)file_handle.handle.stream.handle);
        !          2406:                                                if (c == '#') {
        !          2407:                                                        while (c != '\n' && c != '\r' && c != EOF) {
        !          2408:                                                                c = php_stream_getc((php_stream*)file_handle.handle.stream.handle);     /* skip to end of line */
        !          2409:                                                        }
        !          2410:                                                        /* handle situations where line is terminated by \r\n */
        !          2411:                                                        if (c == '\r') {
        !          2412:                                                                if (php_stream_getc((php_stream*)file_handle.handle.stream.handle) != '\n') {
        !          2413:                                                                        long pos = php_stream_tell((php_stream*)file_handle.handle.stream.handle);
        !          2414:                                                                        php_stream_seek((php_stream*)file_handle.handle.stream.handle, pos - 1, SEEK_SET);
        !          2415:                                                                }
        !          2416:                                                        }
        !          2417:                                                        CG(start_lineno) = 2;
        !          2418:                                                } else {
        !          2419:                                                        php_stream_rewind((php_stream*)file_handle.handle.stream.handle);
        !          2420:                                                }
        !          2421:                                                break;
        !          2422:                                        case ZEND_HANDLE_MAPPED:
        !          2423:                                                if (file_handle.handle.stream.mmap.buf[0] == '#') {
        !          2424:                                                    int i = 1;
        !          2425: 
        !          2426:                                                    c = file_handle.handle.stream.mmap.buf[i++];
        !          2427:                                                        while (c != '\n' && c != '\r' && c != EOF) {
        !          2428:                                                                c = file_handle.handle.stream.mmap.buf[i++];
        !          2429:                                                        }
        !          2430:                                                        if (c == '\r') {
        !          2431:                                                                if (file_handle.handle.stream.mmap.buf[i] == '\n') {
        !          2432:                                                                        i++;
        !          2433:                                                                }
        !          2434:                                                        }
        !          2435:                                                        file_handle.handle.stream.mmap.buf += i;
        !          2436:                                                        file_handle.handle.stream.mmap.len -= i;
        !          2437:                                                }
        !          2438:                                                break;
        !          2439:                                        default:
        !          2440:                                                break;
1.1       misho    2441:                                }
                   2442:                        }
                   2443: 
                   2444:                        switch (behavior) {
                   2445:                                case PHP_MODE_STANDARD:
                   2446:                                        php_execute_script(&file_handle TSRMLS_CC);
                   2447:                                        break;
                   2448:                                case PHP_MODE_LINT:
                   2449:                                        PG(during_request_startup) = 0;
                   2450:                                        exit_status = php_lint_script(&file_handle TSRMLS_CC);
                   2451:                                        if (exit_status == SUCCESS) {
                   2452:                                                zend_printf("No syntax errors detected in %s\n", file_handle.filename);
                   2453:                                        } else {
                   2454:                                                zend_printf("Errors parsing %s\n", file_handle.filename);
                   2455:                                        }
                   2456:                                        break;
                   2457:                                case PHP_MODE_STRIP:
                   2458:                                        if (open_file_for_scanning(&file_handle TSRMLS_CC) == SUCCESS) {
                   2459:                                                zend_strip(TSRMLS_C);
                   2460:                                                zend_file_handle_dtor(&file_handle TSRMLS_CC);
1.1.1.2 ! misho    2461:                                                php_output_teardown();
1.1       misho    2462:                                        }
                   2463:                                        return SUCCESS;
                   2464:                                        break;
                   2465:                                case PHP_MODE_HIGHLIGHT:
                   2466:                                        {
                   2467:                                                zend_syntax_highlighter_ini syntax_highlighter_ini;
                   2468: 
                   2469:                                                if (open_file_for_scanning(&file_handle TSRMLS_CC) == SUCCESS) {
                   2470:                                                        php_get_highlight_struct(&syntax_highlighter_ini);
                   2471:                                                        zend_highlight(&syntax_highlighter_ini TSRMLS_CC);
                   2472:                                                        if (fastcgi) {
                   2473:                                                                goto fastcgi_request_done;
                   2474:                                                        }
                   2475:                                                        zend_file_handle_dtor(&file_handle TSRMLS_CC);
1.1.1.2 ! misho    2476:                                                        php_output_teardown();
1.1       misho    2477:                                                }
                   2478:                                                return SUCCESS;
                   2479:                                        }
                   2480:                                        break;
                   2481: #if 0
                   2482:                                /* Zeev might want to do something with this one day */
                   2483:                                case PHP_MODE_INDENT:
                   2484:                                        open_file_for_scanning(&file_handle TSRMLS_CC);
                   2485:                                        zend_indent();
                   2486:                                        zend_file_handle_dtor(&file_handle TSRMLS_CC);
1.1.1.2 ! misho    2487:                                        php_output_teardown();
1.1       misho    2488:                                        return SUCCESS;
                   2489:                                        break;
                   2490: #endif
                   2491:                        }
                   2492: 
                   2493: fastcgi_request_done:
                   2494:                        {
                   2495:                                STR_FREE(SG(request_info).path_translated);
                   2496: 
                   2497:                                php_request_shutdown((void *) 0);
                   2498: 
                   2499:                                if (exit_status == 0) {
                   2500:                                        exit_status = EG(exit_status);
                   2501:                                }
                   2502: 
                   2503:                                if (free_query_string && SG(request_info).query_string) {
                   2504:                                        free(SG(request_info).query_string);
                   2505:                                        SG(request_info).query_string = NULL;
                   2506:                                }
                   2507:                        }
                   2508: 
                   2509:                        if (!fastcgi) {
                   2510:                                if (benchmark) {
                   2511:                                        repeats--;
                   2512:                                        if (repeats > 0) {
                   2513:                                                script_file = NULL;
                   2514:                                                php_optind = orig_optind;
                   2515:                                                php_optarg = orig_optarg;
                   2516:                                                continue;
                   2517:                                        }
                   2518:                                }
                   2519:                                break;
                   2520:                        }
                   2521: 
                   2522:                        /* only fastcgi will get here */
                   2523:                        requests++;
                   2524:                        if (max_requests && (requests == max_requests)) {
1.1.1.2 ! misho    2525:                                fcgi_finish_request(request, 1);
1.1       misho    2526:                                if (bindpath) {
                   2527:                                        free(bindpath);
                   2528:                                }
                   2529:                                if (max_requests != 1) {
                   2530:                                        /* no need to return exit_status of the last request */
                   2531:                                        exit_status = 0;
                   2532:                                }
                   2533:                                break;
                   2534:                        }
                   2535:                        /* end of fastcgi loop */
                   2536:                }
1.1.1.2 ! misho    2537:                if (request) {
        !          2538:                        fcgi_destroy_request(request);
        !          2539:                }
1.1       misho    2540:                fcgi_shutdown();
                   2541: 
                   2542:                if (cgi_sapi_module.php_ini_path_override) {
                   2543:                        free(cgi_sapi_module.php_ini_path_override);
                   2544:                }
                   2545:                if (cgi_sapi_module.ini_entries) {
                   2546:                        free(cgi_sapi_module.ini_entries);
                   2547:                }
                   2548:        } zend_catch {
                   2549:                exit_status = 255;
                   2550:        } zend_end_try();
                   2551: 
                   2552: out:
                   2553:        if (benchmark) {
                   2554:                int sec;
                   2555: #ifdef HAVE_GETTIMEOFDAY
                   2556:                int usec;
                   2557: 
                   2558:                gettimeofday(&end, NULL);
                   2559:                sec = (int)(end.tv_sec - start.tv_sec);
                   2560:                if (end.tv_usec >= start.tv_usec) {
                   2561:                        usec = (int)(end.tv_usec - start.tv_usec);
                   2562:                } else {
                   2563:                        sec -= 1;
                   2564:                        usec = (int)(end.tv_usec + 1000000 - start.tv_usec);
                   2565:                }
                   2566:                fprintf(stderr, "\nElapsed time: %d.%06d sec\n", sec, usec);
                   2567: #else
                   2568:                time(&end);
                   2569:                sec = (int)(end - start);
                   2570:                fprintf(stderr, "\nElapsed time: %d sec\n", sec);
                   2571: #endif
                   2572:        }
                   2573: 
                   2574: #ifndef PHP_WIN32
                   2575: parent_out:
                   2576: #endif
                   2577: 
                   2578:        SG(server_context) = NULL;
                   2579:        php_module_shutdown(TSRMLS_C);
                   2580:        sapi_shutdown();
                   2581: 
                   2582: #ifdef ZTS
                   2583:        tsrm_shutdown();
                   2584: #endif
                   2585: 
                   2586: #if defined(PHP_WIN32) && ZEND_DEBUG && 0
                   2587:        _CrtDumpMemoryLeaks();
                   2588: #endif
                   2589: 
                   2590:        return exit_status;
                   2591: }
                   2592: /* }}} */
                   2593: 
                   2594: /*
                   2595:  * Local variables:
                   2596:  * tab-width: 4
                   2597:  * c-basic-offset: 4
                   2598:  * End:
                   2599:  * vim600: sw=4 ts=4 fdm=marker
                   2600:  * vim<600: sw=4 ts=4
                   2601:  */

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