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