Back to index

php5  5.3.10
thttpd.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Author: Sascha Schumann <sascha@schumann.cx>                         |
00016    +----------------------------------------------------------------------+
00017 */
00018 
00019 /* $Id: thttpd.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 #include "php.h"
00022 #include "SAPI.h"
00023 #include "php_main.h"
00024 #include "php_thttpd.h"
00025 #include "php_variables.h"
00026 #include "version.h"
00027 #include "php_ini.h"
00028 #include "zend_highlight.h"
00029 
00030 #include "ext/standard/php_smart_str.h"
00031 
00032 #include <sys/time.h>
00033 #include <sys/types.h>
00034 #include <sys/uio.h>
00035 #include <stdlib.h>
00036 #include <unistd.h>
00037 
00038 #ifdef HAVE_GETNAMEINFO
00039 #include <sys/socket.h>
00040 #include <netdb.h>
00041 #endif
00042 
00043 typedef struct {
00044        httpd_conn *hc;
00045        void (*on_close)(int);
00046 
00047        size_t unconsumed_length;
00048        smart_str sbuf;
00049        int seen_cl;
00050        int seen_cn;
00051 } php_thttpd_globals;
00052 
00053 #define PHP_SYS_CALL(x) do { x } while (n == -1 && errno == EINTR)
00054 
00055 #ifdef PREMIUM_THTTPD
00056 # define do_keep_alive persistent
00057 #endif
00058 
00059 #ifdef ZTS
00060 static int thttpd_globals_id;
00061 #define TG(v) TSRMG(thttpd_globals_id, php_thttpd_globals *, v)
00062 #else
00063 static php_thttpd_globals thttpd_globals;
00064 #define TG(v) (thttpd_globals.v)
00065 #endif
00066 
00067 static int sapi_thttpd_ub_write(const char *str, uint str_length TSRMLS_DC)
00068 {
00069        int n;
00070        uint sent = 0;
00071        
00072        if (TG(sbuf).c != 0) {
00073               smart_str_appendl_ex(&TG(sbuf), str, str_length, 1);
00074               return str_length;
00075        }
00076        
00077        while (str_length > 0) {
00078               PHP_SYS_CALL(n = send(TG(hc)->conn_fd, str, str_length, 0););
00079 
00080               if (n == -1) {
00081                      if (errno == EAGAIN) {
00082                             smart_str_appendl_ex(&TG(sbuf), str, str_length, 1);
00083 
00084                             return sent + str_length;
00085                      } else
00086                             php_handle_aborted_connection();
00087               }
00088 
00089               TG(hc)->bytes_sent += n;
00090               str += n;
00091               sent += n;
00092               str_length -= n;
00093        }
00094 
00095        return sent;
00096 }
00097 
00098 #define COMBINE_HEADERS 64
00099 
00100 #if defined(IOV_MAX)
00101 # if IOV_MAX - 64 <= 0
00102 #  define SERIALIZE_HEADERS
00103 # endif
00104 #endif
00105 
00106 static int do_writev(struct iovec *vec, int nvec, int len TSRMLS_DC)
00107 {
00108        int n;
00109 
00110        assert(nvec <= IOV_MAX);
00111 
00112        if (TG(sbuf).c == 0) {
00113               PHP_SYS_CALL(n = writev(TG(hc)->conn_fd, vec, nvec););
00114 
00115               if (n == -1) {
00116                      if (errno == EAGAIN) {
00117                             n = 0;
00118                      } else {
00119                             php_handle_aborted_connection();
00120                      }
00121               }
00122 
00123 
00124               TG(hc)->bytes_sent += n;
00125        } else {
00126               n = 0;
00127        }
00128 
00129        if (n < len) {
00130               int i;
00131 
00132               /* merge all unwritten data into sbuf */
00133               for (i = 0; i < nvec; vec++, i++) {
00134                      /* has this vector been written completely? */
00135                      if (n >= vec->iov_len) {
00136                             /* yes, proceed */
00137                             n -= vec->iov_len;
00138                             continue;
00139                      }
00140 
00141                      if (n > 0) {
00142                             /* adjust vector */
00143                             vec->iov_base = (char *) vec->iov_base + n;
00144                             vec->iov_len -= n;
00145                             n = 0;
00146                      }
00147 
00148                      smart_str_appendl_ex(&TG(sbuf), vec->iov_base, vec->iov_len, 1);
00149               }
00150        }
00151        
00152        return 0;
00153 }
00154 
00155 #ifdef SERIALIZE_HEADERS
00156 # define ADD_VEC(str,l) smart_str_appendl(&vec_str, (str), (l))
00157 # define VEC_BASE() smart_str vec_str = {0}
00158 # define VEC_FREE() smart_str_free(&vec_str)
00159 #else
00160 # define ADD_VEC(str,l) vec[n].iov_base=str;len += (vec[n].iov_len=l); n++
00161 # define VEC_BASE() struct iovec vec[COMBINE_HEADERS]
00162 # define VEC_FREE() do {} while (0)
00163 #endif
00164 
00165 #define ADD_VEC_S(str) ADD_VEC((str), sizeof(str)-1)
00166 
00167 #define CL_TOKEN "Content-length: "
00168 #define CN_TOKEN "Connection: "
00169 #define KA_DO "Connection: keep-alive\r\n"
00170 #define KA_NO "Connection: close\r\n"
00171 #define DEF_CT "Content-Type: text/html\r\n"
00172 
00173 static int sapi_thttpd_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
00174 {
00175        char buf[1024], *p;
00176        VEC_BASE();
00177        int n = 0;
00178        zend_llist_position pos;
00179        sapi_header_struct *h;
00180        size_t len = 0;
00181        
00182        if (!SG(sapi_headers).http_status_line) {
00183               ADD_VEC_S("HTTP/1.1 ");
00184               p = smart_str_print_long(buf+sizeof(buf)-1, 
00185                             SG(sapi_headers).http_response_code);
00186               ADD_VEC(p, strlen(p));
00187               ADD_VEC_S(" HTTP\r\n");
00188        } else {
00189               ADD_VEC(SG(sapi_headers).http_status_line, 
00190                             strlen(SG(sapi_headers).http_status_line));
00191               ADD_VEC("\r\n", 2);
00192        }
00193        TG(hc)->status = SG(sapi_headers).http_response_code;
00194 
00195        if (SG(sapi_headers).send_default_content_type) {
00196               ADD_VEC(DEF_CT, strlen(DEF_CT));
00197        }
00198 
00199        h = zend_llist_get_first_ex(&sapi_headers->headers, &pos);
00200        while (h) {
00201               
00202               switch (h->header[0]) {
00203                      case 'c': case 'C':
00204                             if (!TG(seen_cl) && strncasecmp(h->header, CL_TOKEN, sizeof(CL_TOKEN)-1) == 0) {
00205                                    TG(seen_cl) = 1;
00206                             } else if (!TG(seen_cn) && strncasecmp(h->header, CN_TOKEN, sizeof(CN_TOKEN)-1) == 0) {
00207                                    TG(seen_cn) = 1;
00208                             }
00209               }
00210 
00211               ADD_VEC(h->header, h->header_len);
00212 #ifndef SERIALIZE_HEADERS
00213               if (n >= COMBINE_HEADERS - 1) {
00214                      len = do_writev(vec, n, len TSRMLS_CC);
00215                      n = 0;
00216               }
00217 #endif
00218               ADD_VEC("\r\n", 2);
00219               
00220               h = zend_llist_get_next_ex(&sapi_headers->headers, &pos);
00221        }
00222 
00223        if (TG(seen_cl) && !TG(seen_cn) && TG(hc)->do_keep_alive) {
00224               ADD_VEC(KA_DO, sizeof(KA_DO)-1);
00225        } else {
00226               TG(hc)->do_keep_alive = 0;
00227               ADD_VEC(KA_NO, sizeof(KA_NO)-1);
00228        }
00229               
00230        ADD_VEC("\r\n", 2);
00231 
00232 #ifdef SERIALIZE_HEADERS
00233        sapi_thttpd_ub_write(vec_str.c, vec_str.len TSRMLS_CC);
00234 #else                
00235        do_writev(vec, n, len TSRMLS_CC);
00236 #endif
00237 
00238        VEC_FREE();
00239 
00240        return SAPI_HEADER_SENT_SUCCESSFULLY;
00241 }
00242 
00243 /* to understand this, read cgi_interpose_input() in libhttpd.c */
00244 #define SIZEOF_UNCONSUMED_BYTES() (TG(hc)->read_idx - TG(hc)->checked_idx)
00245 #define CONSUME_BYTES(n) do { TG(hc)->checked_idx += (n); } while (0)
00246 
00247 
00248 static int sapi_thttpd_read_post(char *buffer, uint count_bytes TSRMLS_DC)
00249 {
00250        size_t read_bytes = 0;
00251 
00252        if (TG(unconsumed_length) > 0) {
00253               read_bytes = MIN(TG(unconsumed_length), count_bytes);
00254               memcpy(buffer, TG(hc)->read_buf + TG(hc)->checked_idx, read_bytes);
00255               TG(unconsumed_length) -= read_bytes;
00256               CONSUME_BYTES(read_bytes);
00257        }
00258        
00259        return read_bytes;
00260 }
00261 
00262 static char *sapi_thttpd_read_cookies(TSRMLS_D)
00263 {
00264        return TG(hc)->cookie;
00265 }
00266 
00267 #define BUF_SIZE 512
00268 #define ADD_STRING_EX(name,buf)                                                            \
00269        php_register_variable(name, buf, track_vars_array TSRMLS_CC)
00270 #define ADD_STRING(name) ADD_STRING_EX((name), buf)
00271 
00272 static void sapi_thttpd_register_variables(zval *track_vars_array TSRMLS_DC)
00273 {
00274        char buf[BUF_SIZE + 1];
00275        char *p;
00276 
00277        php_register_variable("PHP_SELF", SG(request_info).request_uri, track_vars_array TSRMLS_CC);
00278        php_register_variable("SERVER_SOFTWARE", SERVER_SOFTWARE, track_vars_array TSRMLS_CC);
00279        php_register_variable("GATEWAY_INTERFACE", "CGI/1.1", track_vars_array TSRMLS_CC);
00280        php_register_variable("REQUEST_METHOD", (char *) SG(request_info).request_method, track_vars_array TSRMLS_CC);
00281        php_register_variable("REQUEST_URI", SG(request_info).request_uri, track_vars_array TSRMLS_CC);
00282        php_register_variable("PATH_TRANSLATED", SG(request_info).path_translated, track_vars_array TSRMLS_CC);
00283 
00284        if (TG(hc)->one_one) {
00285               php_register_variable("SERVER_PROTOCOL", "HTTP/1.1", track_vars_array TSRMLS_CC);
00286        } else {
00287               php_register_variable("SERVER_PROTOCOL", "HTTP/1.0", track_vars_array TSRMLS_CC);
00288        }
00289 
00290        p = httpd_ntoa(&TG(hc)->client_addr);     
00291        
00292        ADD_STRING_EX("REMOTE_ADDR", p);
00293        ADD_STRING_EX("REMOTE_HOST", p);
00294 
00295        ADD_STRING_EX("SERVER_PORT",
00296                      smart_str_print_long(buf + sizeof(buf) - 1,
00297                             TG(hc)->hs->port));
00298 
00299        buf[0] = '/';
00300        memcpy(buf + 1, TG(hc)->pathinfo, strlen(TG(hc)->pathinfo) + 1);
00301        ADD_STRING("PATH_INFO");
00302 
00303        buf[0] = '/';
00304        memcpy(buf + 1, TG(hc)->origfilename, strlen(TG(hc)->origfilename) + 1);
00305        ADD_STRING("SCRIPT_NAME");
00306 
00307 #define CONDADD(name, field)                                                 \
00308        if (TG(hc)->field[0]) {                                                      \
00309               php_register_variable(#name, TG(hc)->field, track_vars_array TSRMLS_CC); \
00310        }
00311 
00312        CONDADD(QUERY_STRING, query);
00313        CONDADD(HTTP_HOST, hdrhost);
00314        CONDADD(HTTP_REFERER, referer);
00315        CONDADD(HTTP_USER_AGENT, useragent);
00316        CONDADD(HTTP_ACCEPT, accept);
00317        CONDADD(HTTP_ACCEPT_LANGUAGE, acceptl);
00318        CONDADD(HTTP_ACCEPT_ENCODING, accepte);
00319        CONDADD(HTTP_COOKIE, cookie);
00320        CONDADD(CONTENT_TYPE, contenttype);
00321        CONDADD(REMOTE_USER, remoteuser);
00322        CONDADD(SERVER_PROTOCOL, protocol);
00323 
00324        if (TG(hc)->contentlength != -1) {
00325               ADD_STRING_EX("CONTENT_LENGTH",
00326                             smart_str_print_long(buf + sizeof(buf) - 1, 
00327                                    TG(hc)->contentlength));
00328        }
00329 
00330        if (TG(hc)->authorization[0])
00331               php_register_variable("AUTH_TYPE", "Basic", track_vars_array TSRMLS_CC);
00332 }
00333 
00334 static PHP_MINIT_FUNCTION(thttpd)
00335 {
00336        return SUCCESS;
00337 }
00338 
00339 static zend_module_entry php_thttpd_module = {
00340        STANDARD_MODULE_HEADER,
00341        "thttpd",
00342        NULL,
00343        PHP_MINIT(thttpd),
00344        NULL,
00345        NULL,
00346        NULL,
00347        NULL, /* info */
00348        NULL,
00349        STANDARD_MODULE_PROPERTIES
00350 };
00351 
00352 static int php_thttpd_startup(sapi_module_struct *sapi_module)
00353 {
00354 #if PHP_API_VERSION >= 20020918
00355        if (php_module_startup(sapi_module, &php_thttpd_module, 1) == FAILURE) {
00356 #else
00357        if (php_module_startup(sapi_module) == FAILURE
00358                      || zend_startup_module(&php_thttpd_module) == FAILURE) {
00359 #endif
00360               return FAILURE;
00361        }
00362        return SUCCESS;
00363 }
00364 
00365 static int sapi_thttpd_get_fd(int *nfd TSRMLS_DC)
00366 {
00367        if (nfd) *nfd = TG(hc)->conn_fd;
00368        return SUCCESS;
00369 }
00370 
00371 static sapi_module_struct thttpd_sapi_module = {
00372        "thttpd",
00373        "thttpd",
00374        
00375        php_thttpd_startup,
00376        php_module_shutdown_wrapper,
00377        
00378        NULL,                                                          /* activate */
00379        NULL,                                                          /* deactivate */
00380 
00381        sapi_thttpd_ub_write,
00382        NULL,
00383        NULL,                                                          /* get uid */
00384        NULL,                                                          /* getenv */
00385 
00386        php_error,
00387        
00388        NULL,
00389        sapi_thttpd_send_headers,
00390        NULL,
00391        sapi_thttpd_read_post,
00392        sapi_thttpd_read_cookies,
00393 
00394        sapi_thttpd_register_variables,
00395        NULL,                                                          /* Log message */
00396        NULL,                                                          /* Get request time */
00397        NULL,                                                          /* Child terminate */
00398 
00399        NULL,                                                          /* php.ini path override */
00400        NULL,                                                          /* Block interruptions */
00401        NULL,                                                          /* Unblock interruptions */
00402 
00403        NULL,
00404        NULL,
00405        NULL,
00406        0,
00407        sapi_thttpd_get_fd
00408 };
00409 
00410 static void thttpd_module_main(int show_source TSRMLS_DC)
00411 {
00412        zend_file_handle file_handle;
00413 
00414        if (php_request_startup(TSRMLS_C) == FAILURE) {
00415               return;
00416        }
00417        
00418        if (show_source) {
00419               zend_syntax_highlighter_ini syntax_highlighter_ini;
00420 
00421               php_get_highlight_struct(&syntax_highlighter_ini);
00422               highlight_file(SG(request_info).path_translated, &syntax_highlighter_ini TSRMLS_CC);
00423        } else {
00424               file_handle.type = ZEND_HANDLE_FILENAME;
00425               file_handle.filename = SG(request_info).path_translated;
00426               file_handle.free_filename = 0;
00427               file_handle.opened_path = NULL;
00428 
00429               php_execute_script(&file_handle TSRMLS_CC);
00430        }
00431        
00432        php_request_shutdown(NULL);
00433 }
00434 
00435 static void thttpd_request_ctor(TSRMLS_D)
00436 {
00437        smart_str s = {0};
00438 
00439        TG(seen_cl) = 0;
00440        TG(seen_cn) = 0;
00441        TG(sbuf).c = 0;
00442        SG(request_info).query_string = TG(hc)->query?strdup(TG(hc)->query):NULL;
00443 
00444        smart_str_appends_ex(&s, TG(hc)->hs->cwd, 1);
00445        smart_str_appends_ex(&s, TG(hc)->expnfilename, 1);
00446        smart_str_0(&s);
00447        SG(request_info).path_translated = s.c;
00448        
00449        s.c = NULL;
00450        smart_str_appendc_ex(&s, '/', 1);
00451        smart_str_appends_ex(&s, TG(hc)->origfilename, 1);
00452        smart_str_0(&s);
00453        SG(request_info).request_uri = s.c;
00454        SG(request_info).request_method = httpd_method_str(TG(hc)->method);
00455        if (TG(hc)->one_one) SG(request_info).proto_num = 1001;
00456        else SG(request_info).proto_num = 1000;
00457        SG(sapi_headers).http_response_code = 200;
00458        if (TG(hc)->contenttype)
00459               SG(request_info).content_type = strdup(TG(hc)->contenttype);
00460        SG(request_info).content_length = TG(hc)->contentlength == -1 ? 0
00461               : TG(hc)->contentlength;
00462 
00463        TG(unconsumed_length) = SG(request_info).content_length;
00464        
00465        php_handle_auth_data(TG(hc)->authorization TSRMLS_CC);
00466 }
00467 
00468 static void thttpd_request_dtor(TSRMLS_D)
00469 {
00470        smart_str_free_ex(&TG(sbuf), 1);
00471        if (SG(request_info).query_string)
00472               free(SG(request_info).query_string);
00473        free(SG(request_info).request_uri);
00474        free(SG(request_info).path_translated);
00475        if (SG(request_info).content_type)
00476               free(SG(request_info).content_type);
00477 }
00478 
00479 #ifdef ZTS
00480 
00481 #ifdef TSRM_ST
00482 #define thread_create_simple_detached(n) st_thread_create(n, NULL, 0, 0)
00483 #define thread_usleep(n) st_usleep(n)
00484 #define thread_exit() st_thread_exit(NULL)
00485 /* No preemption, simple operations are safe */
00486 #define thread_atomic_inc(n) (++n)
00487 #define thread_atomic_dec(n) (--n)
00488 #else
00489 #error No thread primitives available
00490 #endif
00491 
00492 /* We might want to replace this with a STAILQ */
00493 typedef struct qreq {
00494        httpd_conn *hc;
00495        struct qreq *next;
00496 } qreq_t;
00497 
00498 static MUTEX_T qr_lock;
00499 static qreq_t *queued_requests;
00500 static qreq_t *last_qr;
00501 static int nr_free_threads;
00502 static int nr_threads;
00503 static int max_threads = 50;
00504 
00505 #define HANDLE_STRINGS() { \
00506        HANDLE_STR(encodedurl); \
00507        HANDLE_STR(decodedurl); \
00508        HANDLE_STR(origfilename); \
00509        HANDLE_STR(expnfilename); \
00510        HANDLE_STR(pathinfo); \
00511        HANDLE_STR(query); \
00512        HANDLE_STR(referer); \
00513        HANDLE_STR(useragent); \
00514        HANDLE_STR(accept); \
00515        HANDLE_STR(accepte); \
00516        HANDLE_STR(acceptl); \
00517        HANDLE_STR(cookie); \
00518        HANDLE_STR(contenttype); \
00519        HANDLE_STR(authorization); \
00520        HANDLE_STR(remoteuser); \
00521        }
00522 
00523 static httpd_conn *duplicate_conn(httpd_conn *hc, httpd_conn *nhc)
00524 {
00525        memcpy(nhc, hc, sizeof(*nhc));
00526 
00527 #define HANDLE_STR(m) nhc->m = nhc->m ? strdup(nhc->m) : NULL
00528        HANDLE_STRINGS();
00529 #undef HANDLE_STR
00530        
00531        return nhc;
00532 }
00533 
00534 static void destroy_conn(httpd_conn *hc)
00535 {
00536 #define HANDLE_STR(m) if (hc->m) free(hc->m)
00537        HANDLE_STRINGS();
00538 #undef HANDLE_STR
00539 }
00540 
00541 static httpd_conn *dequeue_request(void)
00542 {
00543        httpd_conn *ret = NULL;
00544        qreq_t *m;
00545        
00546        tsrm_mutex_lock(qr_lock);
00547        if (queued_requests) {
00548               m = queued_requests;
00549               ret = m->hc;
00550               if (!(queued_requests = m->next))
00551                      last_qr = NULL;
00552               free(m);
00553        }
00554        tsrm_mutex_unlock(qr_lock);
00555        
00556        return ret;
00557 }
00558 
00559 static void *worker_thread(void *);
00560 
00561 static void queue_request(httpd_conn *hc)
00562 {
00563        qreq_t *m;
00564        httpd_conn *nhc;
00565        
00566        /* Mark as long-running request */
00567        hc->file_address = (char *) 1;
00568 
00569        /*
00570      * We cannot synchronously revoke accesses to hc in the worker
00571         * thread, so we need to pass a copy of hc to the worker thread.
00572         */
00573        nhc = malloc(sizeof *nhc);
00574        duplicate_conn(hc, nhc);
00575        
00576        /* Allocate request queue container */
00577        m = malloc(sizeof *m);
00578        m->hc = nhc;
00579        m->next = NULL;
00580        
00581        tsrm_mutex_lock(qr_lock);
00582        /* Create new threads when reaching a certain threshhold */
00583        if (nr_threads < max_threads && nr_free_threads < 2) {
00584               nr_threads++; /* protected by qr_lock */
00585               
00586               thread_atomic_inc(nr_free_threads);
00587               thread_create_simple_detached(worker_thread);
00588        }
00589        /* Insert container into request queue */
00590        if (queued_requests)
00591               last_qr->next = m;
00592        else
00593               queued_requests = m;
00594        last_qr = m;
00595        tsrm_mutex_unlock(qr_lock);
00596 }
00597 
00598 static off_t thttpd_real_php_request(httpd_conn *hc, int TSRMLS_DC);
00599 
00600 static void *worker_thread(void *dummy)
00601 {
00602        int do_work = 50;
00603        httpd_conn *hc;
00604 
00605        while (do_work) {
00606               hc = dequeue_request();
00607 
00608               if (!hc) {
00609 /*                   do_work--; */
00610                      thread_usleep(500000);
00611                      continue;
00612               }
00613 /*            do_work = 50; */
00614 
00615               thread_atomic_dec(nr_free_threads);
00616 
00617               thttpd_real_php_request(hc, 0 TSRMLS_CC);
00618               shutdown(hc->conn_fd, 0);
00619               destroy_conn(hc);
00620               free(hc);
00621 
00622               thread_atomic_inc(nr_free_threads);
00623        }
00624        thread_atomic_dec(nr_free_threads);
00625        thread_atomic_dec(nr_threads);
00626        thread_exit();
00627 }
00628 
00629 static void remove_dead_conn(int fd)
00630 {
00631        qreq_t *m, *prev = NULL;
00632 
00633        tsrm_mutex_lock(qr_lock);
00634        m = queued_requests;
00635        while (m) {
00636               if (m->hc->conn_fd == fd) {
00637                      if (prev)
00638                             if (!(prev->next = m->next))
00639                                    last_qr = prev;
00640                      else
00641                             if (!(queued_requests = m->next))
00642                                    last_qr = NULL;
00643                      destroy_conn(m->hc);
00644                      free(m->hc);
00645                      free(m);
00646                      break;
00647               }
00648               prev = m;
00649               m = m->next;
00650        }
00651        tsrm_mutex_unlock(qr_lock);
00652 }
00653 
00654 #endif
00655 
00656 static off_t thttpd_real_php_request(httpd_conn *hc, int show_source TSRMLS_DC)
00657 {
00658        TG(hc) = hc;
00659        hc->bytes_sent = 0;
00660 
00661        if (hc->contentlength != -1) {
00662               hc->should_linger = 1;
00663               hc->do_keep_alive = 0;
00664        }
00665        
00666        if (hc->contentlength != -1
00667                      && SIZEOF_UNCONSUMED_BYTES() < hc->contentlength) {
00668               hc->read_body_into_mem = 1;
00669               return 0;
00670        }
00671        
00672        thttpd_request_ctor(TSRMLS_C);
00673 
00674        thttpd_module_main(show_source TSRMLS_CC);
00675 
00676        /* disable kl, if no content-length was seen or Connection: was set */
00677        if (TG(seen_cl) == 0 || TG(seen_cn) == 1) {
00678               TG(hc)->do_keep_alive = 0;
00679        }
00680        
00681        if (TG(sbuf).c != 0) {
00682               if (TG(hc)->response)
00683                      free(TG(hc)->response);
00684               
00685               TG(hc)->response = TG(sbuf).c;
00686               TG(hc)->responselen = TG(sbuf).len;
00687               TG(hc)->maxresponse = TG(sbuf).a;
00688 
00689               TG(sbuf).c = 0;
00690               TG(sbuf).len = 0;
00691               TG(sbuf).a = 0;
00692        }
00693 
00694        thttpd_request_dtor(TSRMLS_C);
00695 
00696        return 0;
00697 }
00698 
00699 off_t thttpd_php_request(httpd_conn *hc, int show_source)
00700 {
00701 #ifdef ZTS
00702        queue_request(hc);
00703 #else
00704        TSRMLS_FETCH();
00705        return thttpd_real_php_request(hc, show_source TSRMLS_CC);
00706 #endif
00707 }
00708 
00709 void thttpd_register_on_close(void (*arg)(int)) 
00710 {
00711        TSRMLS_FETCH();
00712        TG(on_close) = arg;
00713 }
00714 
00715 void thttpd_closed_conn(int fd)
00716 {
00717        TSRMLS_FETCH();
00718        if (TG(on_close)) TG(on_close)(fd);
00719 }
00720 
00721 int thttpd_get_fd(void)
00722 {
00723        TSRMLS_FETCH();
00724        return TG(hc)->conn_fd;
00725 }
00726 
00727 void thttpd_set_dont_close(void)
00728 {
00729        TSRMLS_FETCH();
00730 #ifndef PREMIUM_THTTPD
00731        TG(hc)->file_address = (char *) 1;
00732 #endif
00733 }
00734 
00735 
00736 void thttpd_php_init(void)
00737 {
00738        char *ini;
00739 
00740 #ifdef ZTS
00741        tsrm_startup(1, 1, 0, NULL);
00742        ts_allocate_id(&thttpd_globals_id, sizeof(php_thttpd_globals), NULL, NULL);
00743        qr_lock = tsrm_mutex_alloc();
00744        thttpd_register_on_close(remove_dead_conn);
00745 #endif
00746 
00747        if ((ini = getenv("PHP_INI_PATH"))) {
00748               thttpd_sapi_module.php_ini_path_override = ini;
00749        }
00750 
00751        sapi_startup(&thttpd_sapi_module);
00752        thttpd_sapi_module.startup(&thttpd_sapi_module);
00753        
00754        {
00755               TSRMLS_FETCH();
00756 
00757               SG(server_context) = (void *) 1;
00758        }
00759 }
00760 
00761 void thttpd_php_shutdown(void)
00762 {
00763        TSRMLS_FETCH();
00764 
00765        if (SG(server_context) != NULL) {
00766               thttpd_sapi_module.shutdown(&thttpd_sapi_module);
00767               sapi_shutdown();
00768 #ifdef ZTS
00769               tsrm_shutdown();
00770 #endif
00771        }
00772 }