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

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
1.1.1.4 ! misho       5:    | Copyright (c) 1997-2014 The PHP Group                                |
1.1       misho       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: 
1.1.1.2   misho      19: /* $Id$ */
1.1       misho      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);
1.1.1.3   misho     582:        /* Create new threads when reaching a certain threshold */
1.1       misho     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>