File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / sapi / thttpd / thttpd.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:34:35 2012 UTC (12 years, 1 month ago) by misho
Branches: php, MAIN
CVS tags: v5_4_3elwix, v5_4_17p0, HEAD
php 5.4.3+patches

    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,v 1.1.1.2 2012/05/29 12:34:35 misho Exp $ */
   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>