File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / sapi / tux / php_tux.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 20:04:02 2014 UTC (10 years, 1 month ago) by misho
Branches: php, MAIN
CVS tags: v5_4_29, HEAD
php 5.4.29

    1: /*
    2:    +----------------------------------------------------------------------+
    3:    | PHP Version 5                                                        |
    4:    +----------------------------------------------------------------------+
    5:    | Copyright (c) 1997-2014 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: #include "php.h"
   20: #include "SAPI.h"
   21: #include "php_main.h"
   22: #include "php_variables.h"
   23: 
   24: #include "ext/standard/php_smart_str.h"
   25: 
   26: #include "tuxmodule.h"
   27: 
   28: #include <sys/uio.h>
   29: 
   30: #if 0
   31: #include <pthread.h>
   32: #endif
   33: 
   34: void tux_closed_conn(int fd);
   35: 
   36: enum {
   37: 	PHP_TUX_BACKGROUND_CONN = 1
   38: };
   39: 
   40: typedef struct {
   41: 	user_req_t *req;
   42: 	void (*on_close)(int);
   43: 	int tux_action;
   44: 	struct iovec *header_vec;
   45: 	int number_vec;
   46: } php_tux_globals;
   47: 
   48: static php_tux_globals tux_globals;
   49: 
   50: #define TG(v) (tux_globals.v)
   51: 
   52: static int sapi_tux_ub_write(const char *str, uint str_length TSRMLS_DC)
   53: {
   54: 	int n;
   55: 	int m;
   56: 	const char *estr;
   57: 	
   58: 	/* combine headers and body */
   59: 	if (TG(number_vec)) {
   60: 		struct iovec *vec = TG(header_vec);
   61: 		
   62: 		n = TG(number_vec);
   63: 		vec[n].iov_base = (void *) str;
   64: 		vec[n++].iov_len = str_length;
   65: 		
   66: 		/* XXX: this might need more complete error handling */
   67: 		if ((m = writev(TG(req)->sock, vec, n)) == -1 && errno == EPIPE)
   68: 			php_handle_aborted_connection();
   69: 
   70: 		if (m > 0)
   71: 			TG(req)->bytes_sent += str_length;
   72: 
   73: 		TG(number_vec) = 0;
   74: 		return str_length;
   75: 	}
   76: 
   77: 	estr = str + str_length;
   78: 	
   79: 	while (str < estr) {
   80: 		n = send(TG(req)->sock, str, estr - str, 0);
   81: 
   82: 		if (n == -1 && errno == EPIPE)
   83: 			php_handle_aborted_connection();
   84: 		if (n == -1 && errno == EAGAIN)
   85: 			continue;
   86: 		if (n <= 0) 
   87: 			return n;
   88: 
   89: 		str += n;
   90: 	}
   91: 
   92: 	n = str_length - (estr - str);
   93: 	
   94: 	TG(req)->bytes_sent += n;
   95: 
   96: 	return n;
   97: }
   98: 
   99: static int sapi_tux_send_headers(sapi_headers_struct *sapi_headers)
  100: {
  101: 	char buf[1024];
  102: 	struct iovec *vec;
  103: 	int n;
  104: 	int max_headers;
  105: 	zend_llist_position pos;
  106: 	sapi_header_struct *h;
  107: 	size_t len;
  108: 	char *status_line;
  109: 	int locate_cl;
  110: 	TSRMLS_FETCH();
  111: 	
  112: 	max_headers = 30;
  113: 	n = 1;
  114: 	
  115: 	vec = malloc(sizeof(struct iovec) * max_headers);
  116: 	status_line = malloc(30);
  117: 	
  118: 	/* safe sprintf use */
  119: 	len = slprintf(status_line, 30, "HTTP/1.1 %d NA\r\n", SG(sapi_headers).http_response_code);
  120: 	
  121: 	vec[0].iov_base = status_line;
  122: 	vec[0].iov_len = len;
  123: 	
  124: 	TG(req)->http_status = SG(sapi_headers).http_response_code;
  125: 
  126: 	if (TG(tux_action) == TUX_ACTION_FINISH_CLOSE_REQ && TG(req)->http_version == HTTP_1_1)
  127: 		locate_cl = 1;
  128: 	else
  129: 		locate_cl = 0;
  130: 	
  131: 	h = zend_llist_get_first_ex(&sapi_headers->headers, &pos);
  132: 	while (h) {
  133: 		if (locate_cl 
  134: 				&& strncasecmp(h->header, "Content-length:", sizeof("Content-length:")-1) == 0) {
  135: 			TG(tux_action) = TUX_ACTION_FINISH_REQ;
  136: 			locate_cl = 0;
  137: 		}
  138: 			
  139: 		vec[n].iov_base = h->header;
  140: 		vec[n++].iov_len = h->header_len;
  141: 		if (n >= max_headers - 3) {
  142: 			max_headers *= 2;
  143: 			vec = realloc(vec, sizeof(struct iovec) * max_headers);
  144: 		}
  145: 		vec[n].iov_base = "\r\n";
  146: 		vec[n++].iov_len = 2;
  147: 		
  148: 		h = zend_llist_get_next_ex(&sapi_headers->headers, &pos);
  149: 	}
  150: 
  151: 	vec[n].iov_base = "\r\n";
  152: 	vec[n++].iov_len = 2;
  153: 
  154: 	TG(number_vec) = n;
  155: 	TG(header_vec) = vec;
  156: 
  157: 	
  158: 	return SAPI_HEADER_SENT_SUCCESSFULLY;
  159: }
  160: 
  161: static int sapi_tux_read_post(char *buffer, uint count_bytes)
  162: {
  163: #if 0
  164: 	int amount = 0;
  165: 	TSRMLS_FETCH();
  166: 
  167: 	TG(req)->objectlen = count_bytes;
  168: 	TG(req)->object_addr = buffer;
  169: 	if (tux(TUX_ACTION_READ_POST_DATA, TG(req)))
  170: 		return 0;
  171: 
  172: 	TG(read_post_data) = 1;
  173: 	
  174: 	return TG(req)->objectlen;
  175: #else
  176: 	return 0;
  177: #endif
  178: }
  179: 
  180: static char *sapi_tux_read_cookies(void)
  181: {
  182: 	TSRMLS_FETCH();
  183: 	
  184: 	return TG(req)->cookies;
  185: }
  186: 
  187: #define BUF_SIZE 512
  188: #define ADD_STRING(name)										\
  189: 	php_register_variable(name, buf, track_vars_array TSRMLS_CC)
  190: 
  191: static void sapi_tux_register_variables(zval *track_vars_array TSRMLS_DC)
  192: {
  193: 	char buf[BUF_SIZE + 1];
  194: 	char *p;
  195: 	sapi_header_line ctr = {0};
  196: 	
  197: 	ctr.line = buf;
  198: 	ctr.line_len = slprintf(buf, sizeof(buf), "Server: %s", TUXAPI_version);
  199: 	sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
  200: 	
  201: 	php_register_variable("PHP_SELF", SG(request_info).request_uri, track_vars_array TSRMLS_CC);
  202: 	php_register_variable("SERVER_SOFTWARE", TUXAPI_version, track_vars_array TSRMLS_CC);
  203: 	php_register_variable("GATEWAY_INTERFACE", "CGI/1.1", track_vars_array TSRMLS_CC);
  204: 	php_register_variable("REQUEST_METHOD", (char *) SG(request_info).request_method, track_vars_array TSRMLS_CC);
  205: 	php_register_variable("DOCUMENT_ROOT", TUXAPI_docroot, track_vars_array TSRMLS_CC);
  206: 	php_register_variable("SERVER_NAME", TUXAPI_servername, track_vars_array TSRMLS_CC);
  207: 	php_register_variable("REQUEST_URI", SG(request_info).request_uri, track_vars_array TSRMLS_CC);
  208: 	php_register_variable("PATH_TRANSLATED", SG(request_info).path_translated, track_vars_array TSRMLS_CC);
  209: 
  210: 	p = inet_ntoa(TG(req)->client_host);
  211: 	/* string representation of IPs are never larger than 512 bytes */
  212: 	if (p) {
  213: 		memcpy(buf, p, strlen(p) + 1);
  214: 		ADD_STRING("REMOTE_ADDR");
  215: 		ADD_STRING("REMOTE_HOST");
  216: 	}
  217: 
  218: 	snprintf(buf, sizeof(buf), "%d", CGI_SERVER_PORT(TG(req)));
  219: 	ADD_STRING("SERVER_PORT");
  220: 
  221: #if 0
  222: 	snprintf(buf, BUF_SIZE, "/%s", TG(hc)->pathinfo);
  223: 	ADD_STRING("PATH_INFO");
  224: 
  225: 	snprintf(buf, BUF_SIZE, "/%s", TG(hc)->origfilename);
  226: 	ADD_STRING("SCRIPT_NAME");
  227: #endif
  228: 
  229: #define CONDADD(name, field) 							\
  230: 	if (TG(req)->field[0]) {								\
  231: 		php_register_variable(#name, TG(req)->field, track_vars_array TSRMLS_CC); \
  232: 	}
  233: 
  234: 	CONDADD(HTTP_REFERER, referer);
  235: 	CONDADD(HTTP_USER_AGENT, user_agent);
  236: 	CONDADD(HTTP_ACCEPT, accept);
  237: 	CONDADD(HTTP_ACCEPT_ENCODING, accept_encoding);
  238: 	CONDADD(HTTP_ACCEPT_LANGUAGE, accept_language);
  239: 	CONDADD(HTTP_COOKIE, cookies);
  240: 	CONDADD(CONTENT_TYPE, content_type);
  241: 
  242: #if 0
  243: 	if (TG(hc)->contentlength != -1) {
  244: 		snprintf(buf, sizeof(buf), "%ld", (long) TG(hc)->contentlength);
  245: 		ADD_STRING("CONTENT_LENGTH");
  246: 	}
  247: #endif
  248: 
  249: #if 0
  250: 	if (TG(hc)->authorization[0])
  251: 		php_register_variable("AUTH_TYPE", "Basic", track_vars_array TSRMLS_CC);
  252: #endif
  253: }
  254: 
  255: 
  256: static int php_tux_startup(sapi_module_struct *sapi_module)
  257: {
  258: 	if (php_module_startup(sapi_module, NULL, 0)==FAILURE) {
  259: 		return FAILURE;
  260: 	} else {
  261: 		return SUCCESS;
  262: 	}
  263: }
  264: 
  265: static sapi_module_struct tux_sapi_module = {
  266: 	"tux",
  267: 	"tux",
  268: 	
  269: 	php_tux_startup,
  270: 	php_module_shutdown_wrapper,
  271: 	
  272: 	NULL,									/* activate */
  273: 	NULL,									/* deactivate */
  274: 
  275: 	sapi_tux_ub_write,
  276: 	NULL,
  277: 	NULL,									/* get uid */
  278: 	NULL,									/* getenv */
  279: 
  280: 	php_error,
  281: 	
  282: 	NULL,
  283: 	sapi_tux_send_headers,
  284: 	NULL,
  285: 	sapi_tux_read_post,
  286: 	sapi_tux_read_cookies,
  287: 
  288: 	sapi_tux_register_variables,
  289: 	NULL,									/* Log message */
  290: 	NULL,									/* Get request time */
  291: 	NULL,									/* Child terminate */
  292: 
  293: 	STANDARD_SAPI_MODULE_PROPERTIES
  294: };
  295: 
  296: static void tux_module_main(TSRMLS_D)
  297: {
  298: 	zend_file_handle file_handle;
  299: 
  300: 	file_handle.type = ZEND_HANDLE_FILENAME;
  301: 	file_handle.filename = SG(request_info).path_translated;
  302: 	file_handle.free_filename = 0;
  303: 	file_handle.opened_path = NULL;
  304: 
  305: 	if (php_request_startup(TSRMLS_C) == FAILURE) {
  306: 		return;
  307: 	}
  308: 	
  309: 	php_execute_script(&file_handle TSRMLS_CC);
  310: 	php_request_shutdown(NULL);
  311: }
  312: 
  313: static void tux_request_ctor(TSRMLS_D)
  314: {
  315: 	char buf[1024];
  316: 	int offset;
  317: 	size_t filename_len;
  318: 	size_t cwd_len;
  319: 	smart_str s = {0};
  320: 	char *p;
  321: 
  322: 	TG(number_vec) = 0;	
  323: 	TG(header_vec) = NULL;
  324: 	SG(request_info).query_string = strdup(TG(req)->query);
  325: 
  326: 	smart_str_appends_ex(&s, "/", 1);
  327: 	smart_str_appends_ex(&s, TG(req)->query, 1);
  328: 	smart_str_0(&s);
  329: 	p = strchr(s.c, '&');
  330: 	if (p)
  331: 		*p = '\0';
  332: 	SG(request_info).path_translated = s.c;
  333: 	
  334: 	s.c = NULL;
  335: 	smart_str_appendc_ex(&s, '/', 1);
  336: 	smart_str_appends_ex(&s, TG(req)->objectname, 1);
  337: 	smart_str_0(&s);
  338: 	SG(request_info).request_uri = s.c;
  339: 	SG(request_info).request_method = CGI_REQUEST_METHOD(TG(req));
  340: 	if(TG(req)->http_version == HTTP_1_1) SG(request_info).proto_num = 1001;
  341: 	else SG(request_info).proto_num = 1000;
  342: 	SG(sapi_headers).http_response_code = 200;
  343: 	SG(request_info).content_type = TG(req)->content_type;
  344: 	SG(request_info).content_length = 0; /* TG(req)->contentlength; */
  345: 
  346: #if 0
  347: 	php_handle_auth_data(TG(hc)->authorization TSRMLS_CC);
  348: #endif
  349: }
  350: 
  351: static void tux_request_dtor(TSRMLS_D)
  352: {
  353: 	if (TG(header_vec)) {
  354: 		/* free status_line */
  355: 		free(TG(header_vec)[0].iov_base);
  356: 		free(TG(header_vec));
  357: 	}
  358: 	if (SG(request_info).query_string)
  359: 		free(SG(request_info).query_string);
  360: 	free(SG(request_info).request_uri);
  361: 	free(SG(request_info).path_translated);
  362: }
  363: 
  364: #if 0
  365: static void *separate_thread(void *bla)
  366: {
  367: 	int fd;
  368: 	int i = 0;
  369: 	
  370: 	fd = (int) bla;
  371: 
  372: 	while (i++ < 5) {
  373: 		send(fd, "test<br />\n", 9, 0);
  374: 		sleep(1);
  375: 	}
  376: 	
  377: 	tux(TUX_ACTION_CONTINUE_REQ, (user_req_t *) fd);
  378: 	/* We HAVE to trigger some event on the fd. Otherwise
  379: 	   fast_thread won't wake up, so that the eventloop
  380: 	   won't be entered -> TUX hangs */
  381: 	shutdown(fd, 2);
  382: 	pthread_exit(NULL);
  383: }
  384: #endif
  385: 
  386: int TUXAPI_handle_events(user_req_t *req)
  387: {
  388: 	TSRMLS_FETCH();
  389: 
  390: 	if (req->event == PHP_TUX_BACKGROUND_CONN) {
  391: 		tux_closed_conn(req->sock);
  392: 		return tux(TUX_ACTION_FINISH_CLOSE_REQ, req);
  393: 	}
  394: 	
  395: 	TG(req) = req;
  396: 	TG(tux_action) = TUX_ACTION_FINISH_CLOSE_REQ;
  397: 	
  398: 	tux_request_ctor(TSRMLS_C);
  399: 
  400: 	tux_module_main(TSRMLS_C);
  401: 
  402: 	tux_request_dtor(TSRMLS_C);
  403: 
  404: 	return tux(TG(tux_action), req);
  405: }
  406: 
  407: void tux_register_on_close(void (*arg)(int)) 
  408: {
  409: 	TG(on_close) = arg;
  410: }
  411: 
  412: void tux_closed_conn(int fd)
  413: {
  414: 	TSRMLS_FETCH();
  415: 
  416: 	if (TG(on_close)) TG(on_close)(fd);
  417: }
  418: 
  419: int tux_get_fd(void)
  420: {
  421: 	TSRMLS_FETCH();
  422: 	
  423: 	return TG(req)->sock;
  424: }
  425: 
  426: void tux_set_dont_close(void)
  427: {
  428: 	TSRMLS_FETCH();
  429: 
  430: 	TG(req)->event = PHP_TUX_BACKGROUND_CONN;
  431: 	tux(TUX_ACTION_POSTPONE_REQ, TG(req));
  432: 	TG(tux_action) = TUX_ACTION_EVENTLOOP;
  433: }
  434: 
  435: void TUXAPI_init(void)
  436: {
  437: 	sapi_startup(&tux_sapi_module);
  438: 	tux_sapi_module.startup(&tux_sapi_module);
  439: 	SG(server_context) = (void *) 1;
  440: }
  441: 
  442: void doesnotmatter_fini(void)
  443: {
  444: 	if (SG(server_context) != NULL) {
  445: 		tux_sapi_module.shutdown(&tux_sapi_module);
  446: 		sapi_shutdown();
  447: 	}
  448: }
  449: 
  450: /*
  451:  * Local variables:
  452:  * tab-width: 4
  453:  * c-basic-offset: 4
  454:  * End:
  455:  * vim600: sw=4 ts=4 fdm=marker
  456:  * vim<600: sw=4 ts=4
  457:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>