root/sapi/thttpd/thttpd.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sapi_thttpd_ub_write
  2. do_writev
  3. sapi_thttpd_send_headers
  4. sapi_thttpd_read_post
  5. sapi_thttpd_read_cookies
  6. sapi_thttpd_register_variables
  7. PHP_MINIT_FUNCTION
  8. php_thttpd_startup
  9. sapi_thttpd_get_fd
  10. thttpd_module_main
  11. thttpd_request_ctor
  12. thttpd_request_dtor
  13. duplicate_conn
  14. destroy_conn
  15. dequeue_request
  16. queue_request
  17. worker_thread
  18. remove_dead_conn
  19. thttpd_real_php_request
  20. thttpd_php_request
  21. thttpd_register_on_close
  22. thttpd_closed_conn
  23. thttpd_get_fd
  24. thttpd_set_dont_close
  25. thttpd_php_init
  26. thttpd_php_shutdown

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 5                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 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$ */
  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 threshold */
 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 }

/* [<][>][^][v][top][bottom][index][help] */