Return to thttpd.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / sapi / thttpd |
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: }