Annotation of embedaddon/php/sapi/thttpd/thttpd.c, revision 1.1

1.1     ! misho       1: /*
        !             2:    +----------------------------------------------------------------------+
        !             3:    | PHP Version 5                                                        |
        !             4:    +----------------------------------------------------------------------+
        !             5:    | Copyright (c) 1997-2012 The PHP Group                                |
        !             6:    +----------------------------------------------------------------------+
        !             7:    | This source file is subject to version 3.01 of the PHP license,      |
        !             8:    | that is bundled with this package in the file LICENSE, and is        |
        !             9:    | available through the world-wide-web at the following url:           |
        !            10:    | http://www.php.net/license/3_01.txt                                  |
        !            11:    | If you did not receive a copy of the PHP license and are unable to   |
        !            12:    | obtain it through the world-wide-web, please send a note to          |
        !            13:    | license@php.net so we can mail you a copy immediately.               |
        !            14:    +----------------------------------------------------------------------+
        !            15:    | Author: Sascha Schumann <sascha@schumann.cx>                         |
        !            16:    +----------------------------------------------------------------------+
        !            17: */
        !            18: 
        !            19: /* $Id: thttpd.c 321634 2012-01-01 13:15:04Z felipe $ */
        !            20: 
        !            21: #include "php.h"
        !            22: #include "SAPI.h"
        !            23: #include "php_main.h"
        !            24: #include "php_thttpd.h"
        !            25: #include "php_variables.h"
        !            26: #include "version.h"
        !            27: #include "php_ini.h"
        !            28: #include "zend_highlight.h"
        !            29: 
        !            30: #include "ext/standard/php_smart_str.h"
        !            31: 
        !            32: #include <sys/time.h>
        !            33: #include <sys/types.h>
        !            34: #include <sys/uio.h>
        !            35: #include <stdlib.h>
        !            36: #include <unistd.h>
        !            37: 
        !            38: #ifdef HAVE_GETNAMEINFO
        !            39: #include <sys/socket.h>
        !            40: #include <netdb.h>
        !            41: #endif
        !            42: 
        !            43: typedef struct {
        !            44:        httpd_conn *hc;
        !            45:        void (*on_close)(int);
        !            46: 
        !            47:        size_t unconsumed_length;
        !            48:        smart_str sbuf;
        !            49:        int seen_cl;
        !            50:        int seen_cn;
        !            51: } php_thttpd_globals;
        !            52: 
        !            53: #define PHP_SYS_CALL(x) do { x } while (n == -1 && errno == EINTR)
        !            54: 
        !            55: #ifdef PREMIUM_THTTPD
        !            56: # define do_keep_alive persistent
        !            57: #endif
        !            58: 
        !            59: #ifdef ZTS
        !            60: static int thttpd_globals_id;
        !            61: #define TG(v) TSRMG(thttpd_globals_id, php_thttpd_globals *, v)
        !            62: #else
        !            63: static php_thttpd_globals thttpd_globals;
        !            64: #define TG(v) (thttpd_globals.v)
        !            65: #endif
        !            66: 
        !            67: static int sapi_thttpd_ub_write(const char *str, uint str_length TSRMLS_DC)
        !            68: {
        !            69:        int n;
        !            70:        uint sent = 0;
        !            71:        
        !            72:        if (TG(sbuf).c != 0) {
        !            73:                smart_str_appendl_ex(&TG(sbuf), str, str_length, 1);
        !            74:                return str_length;
        !            75:        }
        !            76:        
        !            77:        while (str_length > 0) {
        !            78:                PHP_SYS_CALL(n = send(TG(hc)->conn_fd, str, str_length, 0););
        !            79: 
        !            80:                if (n == -1) {
        !            81:                        if (errno == EAGAIN) {
        !            82:                                smart_str_appendl_ex(&TG(sbuf), str, str_length, 1);
        !            83: 
        !            84:                                return sent + str_length;
        !            85:                        } else
        !            86:                                php_handle_aborted_connection();
        !            87:                }
        !            88: 
        !            89:                TG(hc)->bytes_sent += n;
        !            90:                str += n;
        !            91:                sent += n;
        !            92:                str_length -= n;
        !            93:        }
        !            94: 
        !            95:        return sent;
        !            96: }
        !            97: 
        !            98: #define COMBINE_HEADERS 64
        !            99: 
        !           100: #if defined(IOV_MAX)
        !           101: # if IOV_MAX - 64 <= 0
        !           102: #  define SERIALIZE_HEADERS
        !           103: # endif
        !           104: #endif
        !           105: 
        !           106: static int do_writev(struct iovec *vec, int nvec, int len TSRMLS_DC)
        !           107: {
        !           108:        int n;
        !           109: 
        !           110:        assert(nvec <= IOV_MAX);
        !           111: 
        !           112:        if (TG(sbuf).c == 0) {
        !           113:                PHP_SYS_CALL(n = writev(TG(hc)->conn_fd, vec, nvec););
        !           114: 
        !           115:                if (n == -1) {
        !           116:                        if (errno == EAGAIN) {
        !           117:                                n = 0;
        !           118:                        } else {
        !           119:                                php_handle_aborted_connection();
        !           120:                        }
        !           121:                }
        !           122: 
        !           123: 
        !           124:                TG(hc)->bytes_sent += n;
        !           125:        } else {
        !           126:                n = 0;
        !           127:        }
        !           128: 
        !           129:        if (n < len) {
        !           130:                int i;
        !           131: 
        !           132:                /* merge all unwritten data into sbuf */
        !           133:                for (i = 0; i < nvec; vec++, i++) {
        !           134:                        /* has this vector been written completely? */
        !           135:                        if (n >= vec->iov_len) {
        !           136:                                /* yes, proceed */
        !           137:                                n -= vec->iov_len;
        !           138:                                continue;
        !           139:                        }
        !           140: 
        !           141:                        if (n > 0) {
        !           142:                                /* adjust vector */
        !           143:                                vec->iov_base = (char *) vec->iov_base + n;
        !           144:                                vec->iov_len -= n;
        !           145:                                n = 0;
        !           146:                        }
        !           147: 
        !           148:                        smart_str_appendl_ex(&TG(sbuf), vec->iov_base, vec->iov_len, 1);
        !           149:                }
        !           150:        }
        !           151:        
        !           152:        return 0;
        !           153: }
        !           154: 
        !           155: #ifdef SERIALIZE_HEADERS
        !           156: # define ADD_VEC(str,l) smart_str_appendl(&vec_str, (str), (l))
        !           157: # define VEC_BASE() smart_str vec_str = {0}
        !           158: # define VEC_FREE() smart_str_free(&vec_str)
        !           159: #else
        !           160: # define ADD_VEC(str,l) vec[n].iov_base=str;len += (vec[n].iov_len=l); n++
        !           161: # define VEC_BASE() struct iovec vec[COMBINE_HEADERS]
        !           162: # define VEC_FREE() do {} while (0)
        !           163: #endif
        !           164: 
        !           165: #define ADD_VEC_S(str) ADD_VEC((str), sizeof(str)-1)
        !           166: 
        !           167: #define CL_TOKEN "Content-length: "
        !           168: #define CN_TOKEN "Connection: "
        !           169: #define KA_DO "Connection: keep-alive\r\n"
        !           170: #define KA_NO "Connection: close\r\n"
        !           171: #define DEF_CT "Content-Type: text/html\r\n"
        !           172: 
        !           173: static int sapi_thttpd_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
        !           174: {
        !           175:        char buf[1024], *p;
        !           176:        VEC_BASE();
        !           177:        int n = 0;
        !           178:        zend_llist_position pos;
        !           179:        sapi_header_struct *h;
        !           180:        size_t len = 0;
        !           181:        
        !           182:        if (!SG(sapi_headers).http_status_line) {
        !           183:                ADD_VEC_S("HTTP/1.1 ");
        !           184:                p = smart_str_print_long(buf+sizeof(buf)-1, 
        !           185:                                SG(sapi_headers).http_response_code);
        !           186:                ADD_VEC(p, strlen(p));
        !           187:                ADD_VEC_S(" HTTP\r\n");
        !           188:        } else {
        !           189:                ADD_VEC(SG(sapi_headers).http_status_line, 
        !           190:                                strlen(SG(sapi_headers).http_status_line));
        !           191:                ADD_VEC("\r\n", 2);
        !           192:        }
        !           193:        TG(hc)->status = SG(sapi_headers).http_response_code;
        !           194: 
        !           195:        if (SG(sapi_headers).send_default_content_type) {
        !           196:                ADD_VEC(DEF_CT, strlen(DEF_CT));
        !           197:        }
        !           198: 
        !           199:        h = zend_llist_get_first_ex(&sapi_headers->headers, &pos);
        !           200:        while (h) {
        !           201:                
        !           202:                switch (h->header[0]) {
        !           203:                        case 'c': case 'C':
        !           204:                                if (!TG(seen_cl) && strncasecmp(h->header, CL_TOKEN, sizeof(CL_TOKEN)-1) == 0) {
        !           205:                                        TG(seen_cl) = 1;
        !           206:                                } else if (!TG(seen_cn) && strncasecmp(h->header, CN_TOKEN, sizeof(CN_TOKEN)-1) == 0) {
        !           207:                                        TG(seen_cn) = 1;
        !           208:                                }
        !           209:                }
        !           210: 
        !           211:                ADD_VEC(h->header, h->header_len);
        !           212: #ifndef SERIALIZE_HEADERS
        !           213:                if (n >= COMBINE_HEADERS - 1) {
        !           214:                        len = do_writev(vec, n, len TSRMLS_CC);
        !           215:                        n = 0;
        !           216:                }
        !           217: #endif
        !           218:                ADD_VEC("\r\n", 2);
        !           219:                
        !           220:                h = zend_llist_get_next_ex(&sapi_headers->headers, &pos);
        !           221:        }
        !           222: 
        !           223:        if (TG(seen_cl) && !TG(seen_cn) && TG(hc)->do_keep_alive) {
        !           224:                ADD_VEC(KA_DO, sizeof(KA_DO)-1);
        !           225:        } else {
        !           226:                TG(hc)->do_keep_alive = 0;
        !           227:                ADD_VEC(KA_NO, sizeof(KA_NO)-1);
        !           228:        }
        !           229:                
        !           230:        ADD_VEC("\r\n", 2);
        !           231: 
        !           232: #ifdef SERIALIZE_HEADERS
        !           233:        sapi_thttpd_ub_write(vec_str.c, vec_str.len TSRMLS_CC);
        !           234: #else                  
        !           235:        do_writev(vec, n, len TSRMLS_CC);
        !           236: #endif
        !           237: 
        !           238:        VEC_FREE();
        !           239: 
        !           240:        return SAPI_HEADER_SENT_SUCCESSFULLY;
        !           241: }
        !           242: 
        !           243: /* to understand this, read cgi_interpose_input() in libhttpd.c */
        !           244: #define SIZEOF_UNCONSUMED_BYTES() (TG(hc)->read_idx - TG(hc)->checked_idx)
        !           245: #define CONSUME_BYTES(n) do { TG(hc)->checked_idx += (n); } while (0)
        !           246: 
        !           247: 
        !           248: static int sapi_thttpd_read_post(char *buffer, uint count_bytes TSRMLS_DC)
        !           249: {
        !           250:        size_t read_bytes = 0;
        !           251: 
        !           252:        if (TG(unconsumed_length) > 0) {
        !           253:                read_bytes = MIN(TG(unconsumed_length), count_bytes);
        !           254:                memcpy(buffer, TG(hc)->read_buf + TG(hc)->checked_idx, read_bytes);
        !           255:                TG(unconsumed_length) -= read_bytes;
        !           256:                CONSUME_BYTES(read_bytes);
        !           257:        }
        !           258:        
        !           259:        return read_bytes;
        !           260: }
        !           261: 
        !           262: static char *sapi_thttpd_read_cookies(TSRMLS_D)
        !           263: {
        !           264:        return TG(hc)->cookie;
        !           265: }
        !           266: 
        !           267: #define BUF_SIZE 512
        !           268: #define ADD_STRING_EX(name,buf)                                                                        \
        !           269:        php_register_variable(name, buf, track_vars_array TSRMLS_CC)
        !           270: #define ADD_STRING(name) ADD_STRING_EX((name), buf)
        !           271: 
        !           272: static void sapi_thttpd_register_variables(zval *track_vars_array TSRMLS_DC)
        !           273: {
        !           274:        char buf[BUF_SIZE + 1];
        !           275:        char *p;
        !           276: 
        !           277:        php_register_variable("PHP_SELF", SG(request_info).request_uri, track_vars_array TSRMLS_CC);
        !           278:        php_register_variable("SERVER_SOFTWARE", SERVER_SOFTWARE, track_vars_array TSRMLS_CC);
        !           279:        php_register_variable("GATEWAY_INTERFACE", "CGI/1.1", track_vars_array TSRMLS_CC);
        !           280:        php_register_variable("REQUEST_METHOD", (char *) SG(request_info).request_method, track_vars_array TSRMLS_CC);
        !           281:        php_register_variable("REQUEST_URI", SG(request_info).request_uri, track_vars_array TSRMLS_CC);
        !           282:        php_register_variable("PATH_TRANSLATED", SG(request_info).path_translated, track_vars_array TSRMLS_CC);
        !           283: 
        !           284:        if (TG(hc)->one_one) {
        !           285:                php_register_variable("SERVER_PROTOCOL", "HTTP/1.1", track_vars_array TSRMLS_CC);
        !           286:        } else {
        !           287:                php_register_variable("SERVER_PROTOCOL", "HTTP/1.0", track_vars_array TSRMLS_CC);
        !           288:        }
        !           289: 
        !           290:        p = httpd_ntoa(&TG(hc)->client_addr);   
        !           291:        
        !           292:        ADD_STRING_EX("REMOTE_ADDR", p);
        !           293:        ADD_STRING_EX("REMOTE_HOST", p);
        !           294: 
        !           295:        ADD_STRING_EX("SERVER_PORT",
        !           296:                        smart_str_print_long(buf + sizeof(buf) - 1,
        !           297:                                TG(hc)->hs->port));
        !           298: 
        !           299:        buf[0] = '/';
        !           300:        memcpy(buf + 1, TG(hc)->pathinfo, strlen(TG(hc)->pathinfo) + 1);
        !           301:        ADD_STRING("PATH_INFO");
        !           302: 
        !           303:        buf[0] = '/';
        !           304:        memcpy(buf + 1, TG(hc)->origfilename, strlen(TG(hc)->origfilename) + 1);
        !           305:        ADD_STRING("SCRIPT_NAME");
        !           306: 
        !           307: #define CONDADD(name, field)                                                   \
        !           308:        if (TG(hc)->field[0]) {                                                         \
        !           309:                php_register_variable(#name, TG(hc)->field, track_vars_array TSRMLS_CC); \
        !           310:        }
        !           311: 
        !           312:        CONDADD(QUERY_STRING, query);
        !           313:        CONDADD(HTTP_HOST, hdrhost);
        !           314:        CONDADD(HTTP_REFERER, referer);
        !           315:        CONDADD(HTTP_USER_AGENT, useragent);
        !           316:        CONDADD(HTTP_ACCEPT, accept);
        !           317:        CONDADD(HTTP_ACCEPT_LANGUAGE, acceptl);
        !           318:        CONDADD(HTTP_ACCEPT_ENCODING, accepte);
        !           319:        CONDADD(HTTP_COOKIE, cookie);
        !           320:        CONDADD(CONTENT_TYPE, contenttype);
        !           321:        CONDADD(REMOTE_USER, remoteuser);
        !           322:        CONDADD(SERVER_PROTOCOL, protocol);
        !           323: 
        !           324:        if (TG(hc)->contentlength != -1) {
        !           325:                ADD_STRING_EX("CONTENT_LENGTH",
        !           326:                                smart_str_print_long(buf + sizeof(buf) - 1, 
        !           327:                                        TG(hc)->contentlength));
        !           328:        }
        !           329: 
        !           330:        if (TG(hc)->authorization[0])
        !           331:                php_register_variable("AUTH_TYPE", "Basic", track_vars_array TSRMLS_CC);
        !           332: }
        !           333: 
        !           334: static PHP_MINIT_FUNCTION(thttpd)
        !           335: {
        !           336:        return SUCCESS;
        !           337: }
        !           338: 
        !           339: static zend_module_entry php_thttpd_module = {
        !           340:        STANDARD_MODULE_HEADER,
        !           341:        "thttpd",
        !           342:        NULL,
        !           343:        PHP_MINIT(thttpd),
        !           344:        NULL,
        !           345:        NULL,
        !           346:        NULL,
        !           347:        NULL, /* info */
        !           348:        NULL,
        !           349:        STANDARD_MODULE_PROPERTIES
        !           350: };
        !           351: 
        !           352: static int php_thttpd_startup(sapi_module_struct *sapi_module)
        !           353: {
        !           354: #if PHP_API_VERSION >= 20020918
        !           355:        if (php_module_startup(sapi_module, &php_thttpd_module, 1) == FAILURE) {
        !           356: #else
        !           357:        if (php_module_startup(sapi_module) == FAILURE
        !           358:                        || zend_startup_module(&php_thttpd_module) == FAILURE) {
        !           359: #endif
        !           360:                return FAILURE;
        !           361:        }
        !           362:        return SUCCESS;
        !           363: }
        !           364: 
        !           365: static int sapi_thttpd_get_fd(int *nfd TSRMLS_DC)
        !           366: {
        !           367:        if (nfd) *nfd = TG(hc)->conn_fd;
        !           368:        return SUCCESS;
        !           369: }
        !           370: 
        !           371: static sapi_module_struct thttpd_sapi_module = {
        !           372:        "thttpd",
        !           373:        "thttpd",
        !           374:        
        !           375:        php_thttpd_startup,
        !           376:        php_module_shutdown_wrapper,
        !           377:        
        !           378:        NULL,                                                                   /* activate */
        !           379:        NULL,                                                                   /* deactivate */
        !           380: 
        !           381:        sapi_thttpd_ub_write,
        !           382:        NULL,
        !           383:        NULL,                                                                   /* get uid */
        !           384:        NULL,                                                                   /* getenv */
        !           385: 
        !           386:        php_error,
        !           387:        
        !           388:        NULL,
        !           389:        sapi_thttpd_send_headers,
        !           390:        NULL,
        !           391:        sapi_thttpd_read_post,
        !           392:        sapi_thttpd_read_cookies,
        !           393: 
        !           394:        sapi_thttpd_register_variables,
        !           395:        NULL,                                                                   /* Log message */
        !           396:        NULL,                                                                   /* Get request time */
        !           397:        NULL,                                                                   /* Child terminate */
        !           398: 
        !           399:        NULL,                                                                   /* php.ini path override */
        !           400:        NULL,                                                                   /* Block interruptions */
        !           401:        NULL,                                                                   /* Unblock interruptions */
        !           402: 
        !           403:        NULL,
        !           404:        NULL,
        !           405:        NULL,
        !           406:        0,
        !           407:        sapi_thttpd_get_fd
        !           408: };
        !           409: 
        !           410: static void thttpd_module_main(int show_source TSRMLS_DC)
        !           411: {
        !           412:        zend_file_handle file_handle;
        !           413: 
        !           414:        if (php_request_startup(TSRMLS_C) == FAILURE) {
        !           415:                return;
        !           416:        }
        !           417:        
        !           418:        if (show_source) {
        !           419:                zend_syntax_highlighter_ini syntax_highlighter_ini;
        !           420: 
        !           421:                php_get_highlight_struct(&syntax_highlighter_ini);
        !           422:                highlight_file(SG(request_info).path_translated, &syntax_highlighter_ini TSRMLS_CC);
        !           423:        } else {
        !           424:                file_handle.type = ZEND_HANDLE_FILENAME;
        !           425:                file_handle.filename = SG(request_info).path_translated;
        !           426:                file_handle.free_filename = 0;
        !           427:                file_handle.opened_path = NULL;
        !           428: 
        !           429:                php_execute_script(&file_handle TSRMLS_CC);
        !           430:        }
        !           431:        
        !           432:        php_request_shutdown(NULL);
        !           433: }
        !           434: 
        !           435: static void thttpd_request_ctor(TSRMLS_D)
        !           436: {
        !           437:        smart_str s = {0};
        !           438: 
        !           439:        TG(seen_cl) = 0;
        !           440:        TG(seen_cn) = 0;
        !           441:        TG(sbuf).c = 0;
        !           442:        SG(request_info).query_string = TG(hc)->query?strdup(TG(hc)->query):NULL;
        !           443: 
        !           444:        smart_str_appends_ex(&s, TG(hc)->hs->cwd, 1);
        !           445:        smart_str_appends_ex(&s, TG(hc)->expnfilename, 1);
        !           446:        smart_str_0(&s);
        !           447:        SG(request_info).path_translated = s.c;
        !           448:        
        !           449:        s.c = NULL;
        !           450:        smart_str_appendc_ex(&s, '/', 1);
        !           451:        smart_str_appends_ex(&s, TG(hc)->origfilename, 1);
        !           452:        smart_str_0(&s);
        !           453:        SG(request_info).request_uri = s.c;
        !           454:        SG(request_info).request_method = httpd_method_str(TG(hc)->method);
        !           455:        if (TG(hc)->one_one) SG(request_info).proto_num = 1001;
        !           456:        else SG(request_info).proto_num = 1000;
        !           457:        SG(sapi_headers).http_response_code = 200;
        !           458:        if (TG(hc)->contenttype)
        !           459:                SG(request_info).content_type = strdup(TG(hc)->contenttype);
        !           460:        SG(request_info).content_length = TG(hc)->contentlength == -1 ? 0
        !           461:                : TG(hc)->contentlength;
        !           462: 
        !           463:        TG(unconsumed_length) = SG(request_info).content_length;
        !           464:        
        !           465:        php_handle_auth_data(TG(hc)->authorization TSRMLS_CC);
        !           466: }
        !           467: 
        !           468: static void thttpd_request_dtor(TSRMLS_D)
        !           469: {
        !           470:        smart_str_free_ex(&TG(sbuf), 1);
        !           471:        if (SG(request_info).query_string)
        !           472:                free(SG(request_info).query_string);
        !           473:        free(SG(request_info).request_uri);
        !           474:        free(SG(request_info).path_translated);
        !           475:        if (SG(request_info).content_type)
        !           476:                free(SG(request_info).content_type);
        !           477: }
        !           478: 
        !           479: #ifdef ZTS
        !           480: 
        !           481: #ifdef TSRM_ST
        !           482: #define thread_create_simple_detached(n) st_thread_create(n, NULL, 0, 0)
        !           483: #define thread_usleep(n) st_usleep(n)
        !           484: #define thread_exit() st_thread_exit(NULL)
        !           485: /* No preemption, simple operations are safe */
        !           486: #define thread_atomic_inc(n) (++n)
        !           487: #define thread_atomic_dec(n) (--n)
        !           488: #else
        !           489: #error No thread primitives available
        !           490: #endif
        !           491: 
        !           492: /* We might want to replace this with a STAILQ */
        !           493: typedef struct qreq {
        !           494:        httpd_conn *hc;
        !           495:        struct qreq *next;
        !           496: } qreq_t;
        !           497: 
        !           498: static MUTEX_T qr_lock;
        !           499: static qreq_t *queued_requests;
        !           500: static qreq_t *last_qr;
        !           501: static int nr_free_threads;
        !           502: static int nr_threads;
        !           503: static int max_threads = 50;
        !           504: 
        !           505: #define HANDLE_STRINGS() { \
        !           506:        HANDLE_STR(encodedurl); \
        !           507:        HANDLE_STR(decodedurl); \
        !           508:        HANDLE_STR(origfilename); \
        !           509:        HANDLE_STR(expnfilename); \
        !           510:        HANDLE_STR(pathinfo); \
        !           511:        HANDLE_STR(query); \
        !           512:        HANDLE_STR(referer); \
        !           513:        HANDLE_STR(useragent); \
        !           514:        HANDLE_STR(accept); \
        !           515:        HANDLE_STR(accepte); \
        !           516:        HANDLE_STR(acceptl); \
        !           517:        HANDLE_STR(cookie); \
        !           518:        HANDLE_STR(contenttype); \
        !           519:        HANDLE_STR(authorization); \
        !           520:        HANDLE_STR(remoteuser); \
        !           521:        }
        !           522: 
        !           523: static httpd_conn *duplicate_conn(httpd_conn *hc, httpd_conn *nhc)
        !           524: {
        !           525:        memcpy(nhc, hc, sizeof(*nhc));
        !           526: 
        !           527: #define HANDLE_STR(m) nhc->m = nhc->m ? strdup(nhc->m) : NULL
        !           528:        HANDLE_STRINGS();
        !           529: #undef HANDLE_STR
        !           530:        
        !           531:        return nhc;
        !           532: }
        !           533: 
        !           534: static void destroy_conn(httpd_conn *hc)
        !           535: {
        !           536: #define HANDLE_STR(m) if (hc->m) free(hc->m)
        !           537:        HANDLE_STRINGS();
        !           538: #undef HANDLE_STR
        !           539: }
        !           540: 
        !           541: static httpd_conn *dequeue_request(void)
        !           542: {
        !           543:        httpd_conn *ret = NULL;
        !           544:        qreq_t *m;
        !           545:        
        !           546:        tsrm_mutex_lock(qr_lock);
        !           547:        if (queued_requests) {
        !           548:                m = queued_requests;
        !           549:                ret = m->hc;
        !           550:                if (!(queued_requests = m->next))
        !           551:                        last_qr = NULL;
        !           552:                free(m);
        !           553:        }
        !           554:        tsrm_mutex_unlock(qr_lock);
        !           555:        
        !           556:        return ret;
        !           557: }
        !           558: 
        !           559: static void *worker_thread(void *);
        !           560: 
        !           561: static void queue_request(httpd_conn *hc)
        !           562: {
        !           563:        qreq_t *m;
        !           564:        httpd_conn *nhc;
        !           565:        
        !           566:        /* Mark as long-running request */
        !           567:        hc->file_address = (char *) 1;
        !           568: 
        !           569:        /*
        !           570:      * We cannot synchronously revoke accesses to hc in the worker
        !           571:         * thread, so we need to pass a copy of hc to the worker thread.
        !           572:         */
        !           573:        nhc = malloc(sizeof *nhc);
        !           574:        duplicate_conn(hc, nhc);
        !           575:        
        !           576:        /* Allocate request queue container */
        !           577:        m = malloc(sizeof *m);
        !           578:        m->hc = nhc;
        !           579:        m->next = NULL;
        !           580:        
        !           581:        tsrm_mutex_lock(qr_lock);
        !           582:        /* Create new threads when reaching a certain threshhold */
        !           583:        if (nr_threads < max_threads && nr_free_threads < 2) {
        !           584:                nr_threads++; /* protected by qr_lock */
        !           585:                
        !           586:                thread_atomic_inc(nr_free_threads);
        !           587:                thread_create_simple_detached(worker_thread);
        !           588:        }
        !           589:        /* Insert container into request queue */
        !           590:        if (queued_requests)
        !           591:                last_qr->next = m;
        !           592:        else
        !           593:                queued_requests = m;
        !           594:        last_qr = m;
        !           595:        tsrm_mutex_unlock(qr_lock);
        !           596: }
        !           597: 
        !           598: static off_t thttpd_real_php_request(httpd_conn *hc, int TSRMLS_DC);
        !           599: 
        !           600: static void *worker_thread(void *dummy)
        !           601: {
        !           602:        int do_work = 50;
        !           603:        httpd_conn *hc;
        !           604: 
        !           605:        while (do_work) {
        !           606:                hc = dequeue_request();
        !           607: 
        !           608:                if (!hc) {
        !           609: /*                     do_work--; */
        !           610:                        thread_usleep(500000);
        !           611:                        continue;
        !           612:                }
        !           613: /*             do_work = 50; */
        !           614: 
        !           615:                thread_atomic_dec(nr_free_threads);
        !           616: 
        !           617:                thttpd_real_php_request(hc, 0 TSRMLS_CC);
        !           618:                shutdown(hc->conn_fd, 0);
        !           619:                destroy_conn(hc);
        !           620:                free(hc);
        !           621: 
        !           622:                thread_atomic_inc(nr_free_threads);
        !           623:        }
        !           624:        thread_atomic_dec(nr_free_threads);
        !           625:        thread_atomic_dec(nr_threads);
        !           626:        thread_exit();
        !           627: }
        !           628: 
        !           629: static void remove_dead_conn(int fd)
        !           630: {
        !           631:        qreq_t *m, *prev = NULL;
        !           632: 
        !           633:        tsrm_mutex_lock(qr_lock);
        !           634:        m = queued_requests;
        !           635:        while (m) {
        !           636:                if (m->hc->conn_fd == fd) {
        !           637:                        if (prev)
        !           638:                                if (!(prev->next = m->next))
        !           639:                                        last_qr = prev;
        !           640:                        else
        !           641:                                if (!(queued_requests = m->next))
        !           642:                                        last_qr = NULL;
        !           643:                        destroy_conn(m->hc);
        !           644:                        free(m->hc);
        !           645:                        free(m);
        !           646:                        break;
        !           647:                }
        !           648:                prev = m;
        !           649:                m = m->next;
        !           650:        }
        !           651:        tsrm_mutex_unlock(qr_lock);
        !           652: }
        !           653: 
        !           654: #endif
        !           655: 
        !           656: static off_t thttpd_real_php_request(httpd_conn *hc, int show_source TSRMLS_DC)
        !           657: {
        !           658:        TG(hc) = hc;
        !           659:        hc->bytes_sent = 0;
        !           660: 
        !           661:        if (hc->contentlength != -1) {
        !           662:                hc->should_linger = 1;
        !           663:                hc->do_keep_alive = 0;
        !           664:        }
        !           665:        
        !           666:        if (hc->contentlength != -1
        !           667:                        && SIZEOF_UNCONSUMED_BYTES() < hc->contentlength) {
        !           668:                hc->read_body_into_mem = 1;
        !           669:                return 0;
        !           670:        }
        !           671:        
        !           672:        thttpd_request_ctor(TSRMLS_C);
        !           673: 
        !           674:        thttpd_module_main(show_source TSRMLS_CC);
        !           675: 
        !           676:        /* disable kl, if no content-length was seen or Connection: was set */
        !           677:        if (TG(seen_cl) == 0 || TG(seen_cn) == 1) {
        !           678:                TG(hc)->do_keep_alive = 0;
        !           679:        }
        !           680:        
        !           681:        if (TG(sbuf).c != 0) {
        !           682:                if (TG(hc)->response)
        !           683:                        free(TG(hc)->response);
        !           684:                
        !           685:                TG(hc)->response = TG(sbuf).c;
        !           686:                TG(hc)->responselen = TG(sbuf).len;
        !           687:                TG(hc)->maxresponse = TG(sbuf).a;
        !           688: 
        !           689:                TG(sbuf).c = 0;
        !           690:                TG(sbuf).len = 0;
        !           691:                TG(sbuf).a = 0;
        !           692:        }
        !           693: 
        !           694:        thttpd_request_dtor(TSRMLS_C);
        !           695: 
        !           696:        return 0;
        !           697: }
        !           698: 
        !           699: off_t thttpd_php_request(httpd_conn *hc, int show_source)
        !           700: {
        !           701: #ifdef ZTS
        !           702:        queue_request(hc);
        !           703: #else
        !           704:        TSRMLS_FETCH();
        !           705:        return thttpd_real_php_request(hc, show_source TSRMLS_CC);
        !           706: #endif
        !           707: }
        !           708: 
        !           709: void thttpd_register_on_close(void (*arg)(int)) 
        !           710: {
        !           711:        TSRMLS_FETCH();
        !           712:        TG(on_close) = arg;
        !           713: }
        !           714: 
        !           715: void thttpd_closed_conn(int fd)
        !           716: {
        !           717:        TSRMLS_FETCH();
        !           718:        if (TG(on_close)) TG(on_close)(fd);
        !           719: }
        !           720: 
        !           721: int thttpd_get_fd(void)
        !           722: {
        !           723:        TSRMLS_FETCH();
        !           724:        return TG(hc)->conn_fd;
        !           725: }
        !           726: 
        !           727: void thttpd_set_dont_close(void)
        !           728: {
        !           729:        TSRMLS_FETCH();
        !           730: #ifndef PREMIUM_THTTPD
        !           731:        TG(hc)->file_address = (char *) 1;
        !           732: #endif
        !           733: }
        !           734: 
        !           735: 
        !           736: void thttpd_php_init(void)
        !           737: {
        !           738:        char *ini;
        !           739: 
        !           740: #ifdef ZTS
        !           741:        tsrm_startup(1, 1, 0, NULL);
        !           742:        ts_allocate_id(&thttpd_globals_id, sizeof(php_thttpd_globals), NULL, NULL);
        !           743:        qr_lock = tsrm_mutex_alloc();
        !           744:        thttpd_register_on_close(remove_dead_conn);
        !           745: #endif
        !           746: 
        !           747:        if ((ini = getenv("PHP_INI_PATH"))) {
        !           748:                thttpd_sapi_module.php_ini_path_override = ini;
        !           749:        }
        !           750: 
        !           751:        sapi_startup(&thttpd_sapi_module);
        !           752:        thttpd_sapi_module.startup(&thttpd_sapi_module);
        !           753:        
        !           754:        {
        !           755:                TSRMLS_FETCH();
        !           756: 
        !           757:                SG(server_context) = (void *) 1;
        !           758:        }
        !           759: }
        !           760: 
        !           761: void thttpd_php_shutdown(void)
        !           762: {
        !           763:        TSRMLS_FETCH();
        !           764: 
        !           765:        if (SG(server_context) != NULL) {
        !           766:                thttpd_sapi_module.shutdown(&thttpd_sapi_module);
        !           767:                sapi_shutdown();
        !           768: #ifdef ZTS
        !           769:                tsrm_shutdown();
        !           770: #endif
        !           771:        }
        !           772: }

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