File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / main / SAPI.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:    | Original design:  Shane Caraveo <shane@caraveo.com>                  |
   16:    | Authors: Andi Gutmans <andi@zend.com>                                |
   17:    |          Zeev Suraski <zeev@zend.com>                                |
   18:    +----------------------------------------------------------------------+
   19: */
   20: 
   21: /* $Id: SAPI.c,v 1.1.1.2 2012/05/29 12:34:35 misho Exp $ */
   22: 
   23: #include <ctype.h>
   24: #include <sys/stat.h>
   25: 
   26: #include "php.h"
   27: #include "SAPI.h"
   28: #include "php_variables.h"
   29: #include "php_ini.h"
   30: #include "ext/standard/php_string.h"
   31: #include "ext/standard/pageinfo.h"
   32: #if (HAVE_PCRE || HAVE_BUNDLED_PCRE) && !defined(COMPILE_DL_PCRE)
   33: #include "ext/pcre/php_pcre.h"
   34: #endif
   35: #ifdef ZTS
   36: #include "TSRM.h"
   37: #endif
   38: #ifdef HAVE_SYS_TIME_H
   39: #include <sys/time.h>
   40: #elif defined(PHP_WIN32)
   41: #include "win32/time.h"
   42: #endif
   43: 
   44: #include "rfc1867.h"
   45: 
   46: #ifdef PHP_WIN32
   47: #define STRCASECMP stricmp
   48: #else
   49: #define STRCASECMP strcasecmp
   50: #endif
   51: 
   52: #include "php_content_types.h"
   53: 
   54: #ifdef ZTS
   55: SAPI_API int sapi_globals_id;
   56: #else
   57: sapi_globals_struct sapi_globals;
   58: #endif
   59: 
   60: static void sapi_globals_ctor(sapi_globals_struct *sapi_globals TSRMLS_DC)
   61: {
   62: 	memset(sapi_globals, 0, sizeof(*sapi_globals));
   63: 	zend_hash_init_ex(&sapi_globals->known_post_content_types, 5, NULL, NULL, 1, 0);
   64: 	php_setup_sapi_content_types(TSRMLS_C);
   65: }
   66: 
   67: static void sapi_globals_dtor(sapi_globals_struct *sapi_globals TSRMLS_DC)
   68: {
   69: 	zend_hash_destroy(&sapi_globals->known_post_content_types);
   70: }
   71: 
   72: /* True globals (no need for thread safety) */
   73: SAPI_API sapi_module_struct sapi_module;
   74: 
   75: 
   76: SAPI_API void sapi_startup(sapi_module_struct *sf)
   77: {
   78: #ifdef ZEND_SIGNALS
   79: 	zend_signal_startup();
   80: #endif
   81: 
   82: 	sf->ini_entries = NULL;
   83: 	sapi_module = *sf;
   84: 
   85: #ifdef ZTS
   86: 	ts_allocate_id(&sapi_globals_id, sizeof(sapi_globals_struct), (ts_allocate_ctor) sapi_globals_ctor, (ts_allocate_dtor) sapi_globals_dtor);
   87: # ifdef PHP_WIN32
   88: 	_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
   89: # endif
   90: #else
   91: 	sapi_globals_ctor(&sapi_globals);
   92: #endif
   93: 
   94: 	virtual_cwd_startup(); /* Could use shutdown to free the main cwd but it would just slow it down for CGI */
   95: 
   96: #ifdef PHP_WIN32
   97: 	tsrm_win32_startup();
   98: #endif
   99: 
  100: 	reentrancy_startup();
  101: }
  102: 
  103: SAPI_API void sapi_shutdown(void)
  104: {
  105: #ifdef ZTS
  106: 	ts_free_id(sapi_globals_id);
  107: #else
  108: 	sapi_globals_dtor(&sapi_globals);
  109: #endif
  110: 
  111: 	reentrancy_shutdown();
  112: 
  113: 	virtual_cwd_shutdown();
  114: 
  115: #ifdef PHP_WIN32
  116: 	tsrm_win32_shutdown();
  117: #endif
  118: }
  119: 
  120: 
  121: SAPI_API void sapi_free_header(sapi_header_struct *sapi_header)
  122: {
  123: 	efree(sapi_header->header);
  124: }
  125: 
  126: /* {{{ proto bool header_register_callback(mixed callback)
  127:    call a header function */
  128: PHP_FUNCTION(header_register_callback)
  129: {
  130: 	zval *callback_func;
  131: 	char *callback_name;
  132: 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &callback_func) == FAILURE) {
  133: 		return;
  134: 	}
  135: 	
  136: 	if (!zend_is_callable(callback_func, 0, &callback_name TSRMLS_CC)) {
  137: 		efree(callback_name);
  138: 		RETURN_FALSE;
  139: 	}
  140: 	efree(callback_name);
  141: 
  142: 	if (SG(callback_func)) {
  143: 		zval_ptr_dtor(&SG(callback_func));
  144: 		SG(fci_cache) = empty_fcall_info_cache;
  145: 	}
  146: 
  147: 	Z_ADDREF_P(callback_func);
  148: 
  149: 	SG(callback_func) = callback_func;
  150: 	
  151: 	RETURN_TRUE;
  152: }
  153: /* }}} */
  154: 
  155: static void sapi_run_header_callback(TSRMLS_D)
  156: {
  157: 	int   error;
  158: 	zend_fcall_info fci;
  159: 	zval *retval_ptr = NULL;
  160: 
  161: 	fci.size = sizeof(fci);
  162: 	fci.function_table = EG(function_table);
  163: 	fci.object_ptr = NULL;
  164: 	fci.function_name = SG(callback_func);
  165: 	fci.retval_ptr_ptr = &retval_ptr;
  166: 	fci.param_count = 0;
  167: 	fci.params = NULL;
  168: 	fci.no_separation = 0;
  169: 	fci.symbol_table = NULL;
  170: 
  171: 	error = zend_call_function(&fci, &SG(fci_cache) TSRMLS_CC);
  172: 	if (error == FAILURE) {
  173: 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not call the sapi_header_callback");
  174: 	} else if (retval_ptr) {
  175: 		zval_ptr_dtor(&retval_ptr);
  176: 	}
  177: }
  178: 
  179: SAPI_API void sapi_handle_post(void *arg TSRMLS_DC)
  180: {
  181: 	if (SG(request_info).post_entry && SG(request_info).content_type_dup) {
  182: 		SG(request_info).post_entry->post_handler(SG(request_info).content_type_dup, arg TSRMLS_CC);
  183: 		if (SG(request_info).post_data) {
  184: 			efree(SG(request_info).post_data);
  185: 			SG(request_info).post_data = NULL;
  186: 		}
  187: 		efree(SG(request_info).content_type_dup);
  188: 		SG(request_info).content_type_dup = NULL;
  189: 	}
  190: }
  191: 
  192: static void sapi_read_post_data(TSRMLS_D)
  193: {
  194: 	sapi_post_entry *post_entry;
  195: 	uint content_type_length = strlen(SG(request_info).content_type);
  196: 	char *content_type = estrndup(SG(request_info).content_type, content_type_length);
  197: 	char *p;
  198: 	char oldchar=0;
  199: 	void (*post_reader_func)(TSRMLS_D) = NULL;
  200: 
  201: 
  202: 	/* dedicated implementation for increased performance:
  203: 	 * - Make the content type lowercase
  204: 	 * - Trim descriptive data, stay with the content-type only
  205: 	 */
  206: 	for (p=content_type; p<content_type+content_type_length; p++) {
  207: 		switch (*p) {
  208: 			case ';':
  209: 			case ',':
  210: 			case ' ':
  211: 				content_type_length = p-content_type;
  212: 				oldchar = *p;
  213: 				*p = 0;
  214: 				break;
  215: 			default:
  216: 				*p = tolower(*p);
  217: 				break;
  218: 		}
  219: 	}
  220: 
  221: 	/* now try to find an appropriate POST content handler */
  222: 	if (zend_hash_find(&SG(known_post_content_types), content_type,
  223: 			content_type_length+1, (void **) &post_entry) == SUCCESS) {
  224: 		/* found one, register it for use */
  225: 		SG(request_info).post_entry = post_entry;
  226: 		post_reader_func = post_entry->post_reader;
  227: 	} else {
  228: 		/* fallback */
  229: 		SG(request_info).post_entry = NULL;
  230: 		if (!sapi_module.default_post_reader) {
  231: 			/* no default reader ? */
  232: 			SG(request_info).content_type_dup = NULL;
  233: 			sapi_module.sapi_error(E_WARNING, "Unsupported content type:  '%s'", content_type);
  234: 			return;
  235: 		}
  236: 	}
  237: 	if (oldchar) {
  238: 		*(p-1) = oldchar;
  239: 	}
  240: 
  241: 	SG(request_info).content_type_dup = content_type;
  242: 
  243: 	if(post_reader_func) {
  244: 		post_reader_func(TSRMLS_C);
  245: 	}
  246: 
  247: 	if(sapi_module.default_post_reader) {
  248: 		sapi_module.default_post_reader(TSRMLS_C);
  249: 	}
  250: }
  251: 
  252: 
  253: SAPI_API SAPI_POST_READER_FUNC(sapi_read_standard_form_data)
  254: {
  255: 	int read_bytes;
  256: 	int allocated_bytes=SAPI_POST_BLOCK_SIZE+1;
  257: 
  258: 	if ((SG(post_max_size) > 0) && (SG(request_info).content_length > SG(post_max_size))) {
  259: 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "POST Content-Length of %ld bytes exceeds the limit of %ld bytes",
  260: 					SG(request_info).content_length, SG(post_max_size));
  261: 		return;
  262: 	}
  263: 	SG(request_info).post_data = emalloc(allocated_bytes);
  264: 
  265: 	for (;;) {
  266: 		read_bytes = sapi_module.read_post(SG(request_info).post_data+SG(read_post_bytes), SAPI_POST_BLOCK_SIZE TSRMLS_CC);
  267: 		if (read_bytes<=0) {
  268: 			break;
  269: 		}
  270: 		SG(read_post_bytes) += read_bytes;
  271: 		if ((SG(post_max_size) > 0) && (SG(read_post_bytes) > SG(post_max_size))) {
  272: 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Actual POST length does not match Content-Length, and exceeds %ld bytes", SG(post_max_size));
  273: 			break;
  274: 		}
  275: 		if (read_bytes < SAPI_POST_BLOCK_SIZE) {
  276: 			break;
  277: 		}
  278: 		if (SG(read_post_bytes)+SAPI_POST_BLOCK_SIZE >= allocated_bytes) {
  279: 			allocated_bytes = SG(read_post_bytes)+SAPI_POST_BLOCK_SIZE+1;
  280: 			SG(request_info).post_data = erealloc(SG(request_info).post_data, allocated_bytes);
  281: 		}
  282: 	}
  283: 	SG(request_info).post_data[SG(read_post_bytes)] = 0;  /* terminating NULL */
  284: 	SG(request_info).post_data_length = SG(read_post_bytes);
  285: }
  286: 
  287: 
  288: static inline char *get_default_content_type(uint prefix_len, uint *len TSRMLS_DC)
  289: {
  290: 	char *mimetype, *charset, *content_type;
  291: 	uint mimetype_len, charset_len;
  292: 
  293: 	if (SG(default_mimetype)) {
  294: 		mimetype = SG(default_mimetype);
  295: 		mimetype_len = strlen(SG(default_mimetype));
  296: 	} else {
  297: 		mimetype = SAPI_DEFAULT_MIMETYPE;
  298: 		mimetype_len = sizeof(SAPI_DEFAULT_MIMETYPE) - 1;
  299: 	}
  300: 	if (SG(default_charset)) {
  301: 		charset = SG(default_charset);
  302: 		charset_len = strlen(SG(default_charset));
  303: 	} else {
  304: 		charset = SAPI_DEFAULT_CHARSET;
  305: 		charset_len = sizeof(SAPI_DEFAULT_CHARSET) - 1;
  306: 	}
  307: 
  308: 	if (*charset && strncasecmp(mimetype, "text/", 5) == 0) {
  309: 		char *p;
  310: 
  311: 		*len = prefix_len + mimetype_len + sizeof("; charset=") - 1 + charset_len;
  312: 		content_type = (char*)emalloc(*len + 1);
  313: 		p = content_type + prefix_len;
  314: 		memcpy(p, mimetype, mimetype_len);
  315: 		p += mimetype_len;
  316: 		memcpy(p, "; charset=", sizeof("; charset=") - 1);
  317: 		p += sizeof("; charset=") - 1;
  318: 		memcpy(p, charset, charset_len + 1);
  319: 	} else {
  320: 		*len = prefix_len + mimetype_len;
  321: 		content_type = (char*)emalloc(*len + 1);
  322: 		memcpy(content_type + prefix_len, mimetype, mimetype_len + 1);
  323: 	}
  324: 	return content_type;
  325: }
  326: 
  327: 
  328: SAPI_API char *sapi_get_default_content_type(TSRMLS_D)
  329: {
  330: 	uint len;
  331: 
  332: 	return get_default_content_type(0, &len TSRMLS_CC);
  333: }
  334: 
  335: 
  336: SAPI_API void sapi_get_default_content_type_header(sapi_header_struct *default_header TSRMLS_DC)
  337: {
  338:     uint len;
  339: 
  340: 	default_header->header = get_default_content_type(sizeof("Content-type: ")-1, &len TSRMLS_CC);
  341: 	default_header->header_len = len;
  342: 	memcpy(default_header->header, "Content-type: ", sizeof("Content-type: ") - 1);
  343: }
  344: 
  345: /*
  346:  * Add charset on content-type header if the MIME type starts with
  347:  * "text/", the default_charset directive is not empty and
  348:  * there is not already a charset option in there.
  349:  *
  350:  * If "mimetype" is non-NULL, it should point to a pointer allocated
  351:  * with emalloc().  If a charset is added, the string will be
  352:  * re-allocated and the new length is returned.  If mimetype is
  353:  * unchanged, 0 is returned.
  354:  *
  355:  */
  356: SAPI_API size_t sapi_apply_default_charset(char **mimetype, size_t len TSRMLS_DC)
  357: {
  358: 	char *charset, *newtype;
  359: 	size_t newlen;
  360: 	charset = SG(default_charset) ? SG(default_charset) : SAPI_DEFAULT_CHARSET;
  361: 
  362: 	if (*mimetype != NULL) {
  363: 		if (*charset && strncmp(*mimetype, "text/", 5) == 0 && strstr(*mimetype, "charset=") == NULL) {
  364: 			newlen = len + (sizeof(";charset=")-1) + strlen(charset);
  365: 			newtype = emalloc(newlen + 1);
  366: 	 		PHP_STRLCPY(newtype, *mimetype, newlen + 1, len);
  367: 			strlcat(newtype, ";charset=", newlen + 1);
  368: 			strlcat(newtype, charset, newlen + 1);
  369: 			efree(*mimetype);
  370: 			*mimetype = newtype;
  371: 			return newlen;
  372: 		}
  373: 	}
  374: 	return 0;
  375: }
  376: 
  377: SAPI_API void sapi_activate_headers_only(TSRMLS_D)
  378: {
  379: 	if (SG(request_info).headers_read == 1)
  380: 		return;
  381: 	SG(request_info).headers_read = 1;
  382: 	zend_llist_init(&SG(sapi_headers).headers, sizeof(sapi_header_struct), 
  383: 			(void (*)(void *)) sapi_free_header, 0);
  384: 	SG(sapi_headers).send_default_content_type = 1;
  385: 
  386: 	/* SG(sapi_headers).http_response_code = 200; */ 
  387: 	SG(sapi_headers).http_status_line = NULL;
  388: 	SG(sapi_headers).mimetype = NULL;
  389: 	SG(read_post_bytes) = 0;
  390: 	SG(request_info).post_data = NULL;
  391: 	SG(request_info).raw_post_data = NULL;
  392: 	SG(request_info).current_user = NULL;
  393: 	SG(request_info).current_user_length = 0;
  394: 	SG(request_info).no_headers = 0;
  395: 	SG(request_info).post_entry = NULL;
  396: 	SG(global_request_time) = 0;
  397: 
  398: 	/*
  399: 	 * It's possible to override this general case in the activate() callback, 
  400: 	 * if necessary.
  401: 	 */
  402: 	if (SG(request_info).request_method && !strcmp(SG(request_info).request_method, "HEAD")) {
  403: 		SG(request_info).headers_only = 1;
  404: 	} else {
  405: 		SG(request_info).headers_only = 0;
  406: 	}
  407: 	if (SG(server_context)) {
  408: 		SG(request_info).cookie_data = sapi_module.read_cookies(TSRMLS_C);
  409: 		if (sapi_module.activate) {
  410: 			sapi_module.activate(TSRMLS_C);
  411: 		}
  412: 	}
  413: 	if (sapi_module.input_filter_init ) {
  414: 		sapi_module.input_filter_init(TSRMLS_C);
  415: 	}
  416: }
  417: 
  418: /*
  419:  * Called from php_request_startup() for every request.
  420:  */
  421: 
  422: SAPI_API void sapi_activate(TSRMLS_D)
  423: {
  424: 	zend_llist_init(&SG(sapi_headers).headers, sizeof(sapi_header_struct), (void (*)(void *)) sapi_free_header, 0);
  425: 	SG(sapi_headers).send_default_content_type = 1;
  426: 
  427: 	/*
  428: 	SG(sapi_headers).http_response_code = 200;
  429: 	*/
  430: 	SG(sapi_headers).http_status_line = NULL;
  431: 	SG(sapi_headers).mimetype = NULL;
  432: 	SG(headers_sent) = 0;
  433: 	SG(callback_run) = 0;
  434: 	SG(callback_func) = NULL;
  435: 	SG(read_post_bytes) = 0;
  436: 	SG(request_info).post_data = NULL;
  437: 	SG(request_info).raw_post_data = NULL;
  438: 	SG(request_info).current_user = NULL;
  439: 	SG(request_info).current_user_length = 0;
  440: 	SG(request_info).no_headers = 0;
  441: 	SG(request_info).post_entry = NULL;
  442: 	SG(request_info).proto_num = 1000; /* Default to HTTP 1.0 */
  443: 	SG(global_request_time) = 0;
  444: 
  445: 	/* It's possible to override this general case in the activate() callback, if necessary. */
  446: 	if (SG(request_info).request_method && !strcmp(SG(request_info).request_method, "HEAD")) {
  447: 		SG(request_info).headers_only = 1;
  448: 	} else {
  449: 		SG(request_info).headers_only = 0;
  450: 	}
  451: 	SG(rfc1867_uploaded_files) = NULL;
  452: 
  453: 	/* Handle request method */
  454: 	if (SG(server_context)) {
  455: 		if (PG(enable_post_data_reading) && SG(request_info).request_method) {
  456: 			if (SG(request_info).content_type && !strcmp(SG(request_info).request_method, "POST")) {
  457: 				/* HTTP POST may contain form data to be processed into variables
  458: 				 * depending on given content type */
  459: 				sapi_read_post_data(TSRMLS_C);
  460: 			} else {
  461: 				/* Any other method with content payload will fill $HTTP_RAW_POST_DATA 
  462: 				 * if it is enabled by always_populate_raw_post_data. 
  463: 				 * It's up to the webserver to decide whether to allow a method or not. */
  464: 				SG(request_info).content_type_dup = NULL;
  465: 				if (sapi_module.default_post_reader) {
  466: 					sapi_module.default_post_reader(TSRMLS_C);
  467: 				}
  468: 			}
  469: 		} else {
  470: 			SG(request_info).content_type_dup = NULL;
  471: 		}
  472: 
  473: 		/* Cookies */
  474: 		SG(request_info).cookie_data = sapi_module.read_cookies(TSRMLS_C);
  475: 
  476: 		if (sapi_module.activate) {
  477: 			sapi_module.activate(TSRMLS_C);
  478: 		}
  479: 	}
  480: 	if (sapi_module.input_filter_init) {
  481: 		sapi_module.input_filter_init(TSRMLS_C);
  482: 	}
  483: }
  484: 
  485: 
  486: static void sapi_send_headers_free(TSRMLS_D)
  487: {
  488: 	if (SG(sapi_headers).http_status_line) {
  489: 		efree(SG(sapi_headers).http_status_line);
  490: 		SG(sapi_headers).http_status_line = NULL;
  491: 	}
  492: }
  493: 	
  494: SAPI_API void sapi_deactivate(TSRMLS_D)
  495: {
  496: 	zend_llist_destroy(&SG(sapi_headers).headers);
  497: 	if (SG(request_info).post_data) {
  498: 		efree(SG(request_info).post_data);
  499: 	}  else 	if (SG(server_context)) {
  500: 		if(sapi_module.read_post) { 
  501: 			/* make sure we've consumed all request input data */
  502: 			char dummy[SAPI_POST_BLOCK_SIZE];
  503: 			int read_bytes;
  504: 
  505: 			while((read_bytes = sapi_module.read_post(dummy, sizeof(dummy)-1 TSRMLS_CC)) > 0) {
  506: 				SG(read_post_bytes) += read_bytes;
  507: 			}
  508: 		}
  509: 	}
  510: 	if (SG(request_info).raw_post_data) {
  511: 		efree(SG(request_info).raw_post_data);
  512: 	} 
  513: 	if (SG(request_info).auth_user) {
  514: 		efree(SG(request_info).auth_user);
  515: 	}
  516: 	if (SG(request_info).auth_password) {
  517: 		efree(SG(request_info).auth_password);
  518: 	}
  519: 	if (SG(request_info).auth_digest) {
  520: 		efree(SG(request_info).auth_digest);
  521: 	}
  522: 	if (SG(request_info).content_type_dup) {
  523: 		efree(SG(request_info).content_type_dup);
  524: 	}
  525: 	if (SG(request_info).current_user) {
  526: 		efree(SG(request_info).current_user);
  527: 	}
  528: 	if (sapi_module.deactivate) {
  529: 		sapi_module.deactivate(TSRMLS_C);
  530: 	}
  531: 	if (SG(rfc1867_uploaded_files)) {
  532: 		destroy_uploaded_files_hash(TSRMLS_C);
  533: 	}
  534: 	if (SG(sapi_headers).mimetype) {
  535: 		efree(SG(sapi_headers).mimetype);
  536: 		SG(sapi_headers).mimetype = NULL;
  537: 	}
  538: 	sapi_send_headers_free(TSRMLS_C);
  539: 	SG(sapi_started) = 0;
  540: 	SG(headers_sent) = 0;
  541: 	SG(callback_run) = 0;
  542: 	if (SG(callback_func)) {
  543: 		zval_ptr_dtor(&SG(callback_func));
  544: 	}
  545: 	SG(request_info).headers_read = 0;
  546: 	SG(global_request_time) = 0;
  547: }
  548: 
  549: 
  550: SAPI_API void sapi_initialize_empty_request(TSRMLS_D)
  551: {
  552: 	SG(server_context) = NULL;
  553: 	SG(request_info).request_method = NULL;
  554: 	SG(request_info).auth_digest = SG(request_info).auth_user = SG(request_info).auth_password = NULL;
  555: 	SG(request_info).content_type_dup = NULL;
  556: }
  557: 
  558: 
  559: static int sapi_extract_response_code(const char *header_line)
  560: {
  561: 	int code = 200;
  562: 	const char *ptr;
  563: 
  564: 	for (ptr = header_line; *ptr; ptr++) {
  565: 		if (*ptr == ' ' && *(ptr + 1) != ' ') {
  566: 			code = atoi(ptr + 1);
  567: 			break;
  568: 		}
  569: 	}
  570: 	
  571: 	return code;
  572: }
  573: 
  574: 
  575: static void sapi_update_response_code(int ncode TSRMLS_DC)
  576: {
  577: 	/* if the status code did not change, we do not want
  578: 	   to change the status line, and no need to change the code */
  579: 	if (SG(sapi_headers).http_response_code == ncode) {
  580: 		return;
  581: 	}
  582: 
  583: 	if (SG(sapi_headers).http_status_line) {
  584: 		efree(SG(sapi_headers).http_status_line);
  585: 		SG(sapi_headers).http_status_line = NULL;
  586: 	}
  587: 	SG(sapi_headers).http_response_code = ncode;
  588: }
  589: 
  590: static int sapi_find_matching_header(void *element1, void *element2)
  591: {
  592: 	int len = strlen((char*)element2);
  593: 	return strncasecmp(((sapi_header_struct*)element1)->header, (char*)element2, len) == 0 && ((sapi_header_struct*)element1)->header[len] == ':';
  594: }
  595: 
  596: SAPI_API int sapi_add_header_ex(char *header_line, uint header_line_len, zend_bool duplicate, zend_bool replace TSRMLS_DC)
  597: {
  598: 	sapi_header_line ctr = {0};
  599: 	int r;
  600: 	
  601: 	ctr.line = header_line;
  602: 	ctr.line_len = header_line_len;
  603: 
  604: 	r = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD,
  605: 			&ctr TSRMLS_CC);
  606: 
  607: 	if (!duplicate)
  608: 		efree(header_line);
  609: 
  610: 	return r;
  611: }
  612: 
  613: static void sapi_header_add_op(sapi_header_op_enum op, sapi_header_struct *sapi_header TSRMLS_DC)
  614: {
  615: 	if (!sapi_module.header_handler ||
  616: 		(SAPI_HEADER_ADD & sapi_module.header_handler(sapi_header, op, &SG(sapi_headers) TSRMLS_CC))) {
  617: 		if (op == SAPI_HEADER_REPLACE) {
  618: 			char *colon_offset = strchr(sapi_header->header, ':');
  619: 
  620: 			if (colon_offset) {
  621: 				char sav = *colon_offset;
  622: 
  623: 				*colon_offset = 0;
  624: 				zend_llist_del_element(&SG(sapi_headers).headers, sapi_header->header, (int(*)(void*, void*))sapi_find_matching_header);
  625: 				*colon_offset = sav;
  626: 			}
  627: 		}
  628: 		zend_llist_add_element(&SG(sapi_headers).headers, (void *) sapi_header);
  629: 	} else {
  630: 		sapi_free_header(sapi_header);
  631: 	}
  632: }
  633: 
  634: SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC)
  635: {
  636: 	sapi_header_struct sapi_header;
  637: 	char *colon_offset;
  638: 	char *header_line;
  639: 	uint header_line_len;
  640: 	int http_response_code;
  641: 
  642: 	if (SG(headers_sent) && !SG(request_info).no_headers) {
  643: 		const char *output_start_filename = php_output_get_start_filename(TSRMLS_C);
  644: 		int output_start_lineno = php_output_get_start_lineno(TSRMLS_C);
  645: 
  646: 		if (output_start_filename) {
  647: 			sapi_module.sapi_error(E_WARNING, "Cannot modify header information - headers already sent by (output started at %s:%d)",
  648: 				output_start_filename, output_start_lineno);
  649: 		} else {
  650: 			sapi_module.sapi_error(E_WARNING, "Cannot modify header information - headers already sent");
  651: 		}
  652: 		return FAILURE;
  653: 	}
  654: 
  655: 	switch (op) {
  656: 		case SAPI_HEADER_SET_STATUS:
  657: 			sapi_update_response_code((int)(zend_intptr_t) arg TSRMLS_CC);
  658: 			return SUCCESS;
  659: 
  660: 		case SAPI_HEADER_ADD:
  661: 		case SAPI_HEADER_REPLACE:
  662: 		case SAPI_HEADER_DELETE: {
  663: 				sapi_header_line *p = arg;
  664: 
  665: 				if (!p->line || !p->line_len) {
  666: 					return FAILURE;
  667: 				}
  668: 				header_line = p->line;
  669: 				header_line_len = p->line_len;
  670: 				http_response_code = p->response_code;
  671: 				break;
  672: 			}
  673: 
  674: 		case SAPI_HEADER_DELETE_ALL:
  675: 			if (sapi_module.header_handler) {
  676: 				sapi_module.header_handler(&sapi_header, op, &SG(sapi_headers) TSRMLS_CC);
  677: 			}
  678: 			zend_llist_clean(&SG(sapi_headers).headers);
  679: 			return SUCCESS;
  680: 
  681: 		default:
  682: 			return FAILURE;
  683: 	}
  684: 
  685: 	header_line = estrndup(header_line, header_line_len);
  686: 
  687: 	/* cut of trailing spaces, linefeeds and carriage-returns */
  688: 	if (header_line_len && isspace(header_line[header_line_len-1])) {
  689: 		do {
  690: 			header_line_len--;
  691: 		} while(header_line_len && isspace(header_line[header_line_len-1]));
  692: 		header_line[header_line_len]='\0';
  693: 	}
  694: 	
  695: 	if (op == SAPI_HEADER_DELETE) {
  696: 		if (strchr(header_line, ':')) {
  697: 			efree(header_line);
  698: 			sapi_module.sapi_error(E_WARNING, "Header to delete may not contain colon.");
  699: 			return FAILURE;
  700: 		}
  701: 		if (sapi_module.header_handler) {
  702: 			sapi_header.header = header_line;
  703: 			sapi_header.header_len = header_line_len;
  704: 			sapi_module.header_handler(&sapi_header, op, &SG(sapi_headers) TSRMLS_CC);
  705: 		}
  706: 		zend_llist_del_element(&SG(sapi_headers).headers, header_line, (int(*)(void*, void*))sapi_find_matching_header);
  707: 		efree(header_line);
  708: 		return SUCCESS;
  709: 	} else {
  710: 		/* new line/NUL character safety check */
  711: 		int i;
  712: 		for (i = 0; i < header_line_len; i++) {
  713: 			/* RFC 2616 allows new lines if followed by SP or HT */
  714: 			int illegal_break =
  715: 					(header_line[i+1] != ' ' && header_line[i+1] != '\t')
  716: 					&& (
  717: 						header_line[i] == '\n'
  718: 						|| (header_line[i] == '\r' && header_line[i+1] != '\n'));
  719: 			if (illegal_break) {
  720: 				efree(header_line);
  721: 				sapi_module.sapi_error(E_WARNING, "Header may not contain "
  722: 						"more than a single header, new line detected");
  723: 				return FAILURE;
  724: 			}
  725: 			if (header_line[i] == '\0') {
  726: 				efree(header_line);
  727: 				sapi_module.sapi_error(E_WARNING, "Header may not contain NUL bytes");
  728: 				return FAILURE;
  729: 			}
  730: 		}
  731: 	}
  732: 
  733: 	sapi_header.header = header_line;
  734: 	sapi_header.header_len = header_line_len;
  735: 
  736: 	/* Check the header for a few cases that we have special support for in SAPI */
  737: 	if (header_line_len>=5 
  738: 		&& !strncasecmp(header_line, "HTTP/", 5)) {
  739: 		/* filter out the response code */
  740: 		sapi_update_response_code(sapi_extract_response_code(header_line) TSRMLS_CC);
  741: 		/* sapi_update_response_code doesn't free the status line if the code didn't change */
  742: 		if (SG(sapi_headers).http_status_line) {
  743: 			efree(SG(sapi_headers).http_status_line);
  744: 		}
  745: 		SG(sapi_headers).http_status_line = header_line;
  746: 		return SUCCESS;
  747: 	} else {
  748: 		colon_offset = strchr(header_line, ':');
  749: 		if (colon_offset) {
  750: 			*colon_offset = 0;
  751: 			if (!STRCASECMP(header_line, "Content-Type")) {
  752: 				char *ptr = colon_offset+1, *mimetype = NULL, *newheader;
  753: 				size_t len = header_line_len - (ptr - header_line), newlen;
  754: 				while (*ptr == ' ') {
  755: 					ptr++;
  756: 					len--;
  757: 				}
  758: 
  759: 				/* Disable possible output compression for images */
  760: 				if (!strncmp(ptr, "image/", sizeof("image/")-1)) {
  761: 					zend_alter_ini_entry("zlib.output_compression", sizeof("zlib.output_compression"), "0", sizeof("0") - 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
  762: 				}
  763: 
  764: 				mimetype = estrdup(ptr);
  765: 				newlen = sapi_apply_default_charset(&mimetype, len TSRMLS_CC);
  766: 				if (!SG(sapi_headers).mimetype){
  767: 					SG(sapi_headers).mimetype = estrdup(mimetype);
  768: 				}
  769: 
  770: 				if (newlen != 0) {
  771: 					newlen += sizeof("Content-type: ");
  772: 					newheader = emalloc(newlen);
  773: 					PHP_STRLCPY(newheader, "Content-type: ", newlen, sizeof("Content-type: ")-1);
  774: 					strlcat(newheader, mimetype, newlen);
  775: 					sapi_header.header = newheader;
  776: 					sapi_header.header_len = newlen - 1;
  777: 					efree(header_line);
  778: 				}
  779: 				efree(mimetype);
  780: 				SG(sapi_headers).send_default_content_type = 0;
  781: 			} else if (!STRCASECMP(header_line, "Content-Length")) {
  782: 				/* Script is setting Content-length. The script cannot reasonably
  783: 				 * know the size of the message body after compression, so it's best
  784: 				 * do disable compression altogether. This contributes to making scripts
  785: 				 * portable between setups that have and don't have zlib compression
  786: 				 * enabled globally. See req #44164 */
  787: 				zend_alter_ini_entry("zlib.output_compression", sizeof("zlib.output_compression"),
  788: 					"0", sizeof("0") - 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
  789: 			} else if (!STRCASECMP(header_line, "Location")) {
  790: 				if ((SG(sapi_headers).http_response_code < 300 ||
  791: 					SG(sapi_headers).http_response_code > 307) &&
  792: 					SG(sapi_headers).http_response_code != 201) {
  793: 					/* Return a Found Redirect if one is not already specified */
  794: 					if (http_response_code) { /* user specified redirect code */
  795: 						sapi_update_response_code(http_response_code TSRMLS_CC);
  796: 					} else if (SG(request_info).proto_num > 1000 && 
  797: 					   SG(request_info).request_method && 
  798: 					   strcmp(SG(request_info).request_method, "HEAD") &&
  799: 					   strcmp(SG(request_info).request_method, "GET")) {
  800: 						sapi_update_response_code(303 TSRMLS_CC);
  801: 					} else {
  802: 						sapi_update_response_code(302 TSRMLS_CC);
  803: 					}
  804: 				}
  805: 			} else if (!STRCASECMP(header_line, "WWW-Authenticate")) { /* HTTP Authentication */
  806: 				sapi_update_response_code(401 TSRMLS_CC); /* authentication-required */
  807: 			}
  808: 			if (sapi_header.header==header_line) {
  809: 				*colon_offset = ':';
  810: 			}
  811: 		}
  812: 	}
  813: 	if (http_response_code) {
  814: 		sapi_update_response_code(http_response_code TSRMLS_CC);
  815: 	}
  816: 	sapi_header_add_op(op, &sapi_header TSRMLS_CC);
  817: 	return SUCCESS;
  818: }
  819: 
  820: 
  821: SAPI_API int sapi_send_headers(TSRMLS_D)
  822: {
  823: 	int retval;
  824: 	int ret = FAILURE;
  825: 
  826: 	if (SG(headers_sent) || SG(request_info).no_headers || SG(callback_run)) {
  827: 		return SUCCESS;
  828: 	}
  829: 
  830: 	/* Success-oriented.  We set headers_sent to 1 here to avoid an infinite loop
  831: 	 * in case of an error situation.
  832: 	 */
  833: 	if (SG(sapi_headers).send_default_content_type && sapi_module.send_headers) {
  834: 		sapi_header_struct default_header;
  835: 	    uint len;
  836: 
  837: 		SG(sapi_headers).mimetype = get_default_content_type(0, &len TSRMLS_CC);
  838: 		default_header.header_len = sizeof("Content-type: ") - 1 + len;
  839: 		default_header.header = emalloc(default_header.header_len + 1);
  840: 		memcpy(default_header.header, "Content-type: ", sizeof("Content-type: ") - 1);
  841: 		memcpy(default_header.header + sizeof("Content-type: ") - 1, SG(sapi_headers).mimetype, len + 1);
  842: 		sapi_header_add_op(SAPI_HEADER_ADD, &default_header TSRMLS_CC);
  843: 		SG(sapi_headers).send_default_content_type = 0;
  844: 	}
  845: 
  846: 	if (SG(callback_func) && !SG(callback_run)) {
  847: 		SG(callback_run) = 1;
  848: 		sapi_run_header_callback(TSRMLS_C);
  849: 	}
  850: 
  851: 	SG(headers_sent) = 1;
  852: 
  853: 	if (sapi_module.send_headers) {
  854: 		retval = sapi_module.send_headers(&SG(sapi_headers) TSRMLS_CC);
  855: 	} else {
  856: 		retval = SAPI_HEADER_DO_SEND;
  857: 	}
  858: 
  859: 	switch (retval) {
  860: 		case SAPI_HEADER_SENT_SUCCESSFULLY:
  861: 			ret = SUCCESS;
  862: 			break;
  863: 		case SAPI_HEADER_DO_SEND: {
  864: 				sapi_header_struct http_status_line;
  865: 				char buf[255];
  866: 
  867: 				if (SG(sapi_headers).http_status_line) {
  868: 					http_status_line.header = SG(sapi_headers).http_status_line;
  869: 					http_status_line.header_len = strlen(SG(sapi_headers).http_status_line);
  870: 				} else {
  871: 					http_status_line.header = buf;
  872: 					http_status_line.header_len = slprintf(buf, sizeof(buf), "HTTP/1.0 %d X", SG(sapi_headers).http_response_code);
  873: 				}
  874: 				sapi_module.send_header(&http_status_line, SG(server_context) TSRMLS_CC);
  875: 			}
  876: 			zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t) sapi_module.send_header, SG(server_context) TSRMLS_CC);
  877: 			if(SG(sapi_headers).send_default_content_type) {
  878: 				sapi_header_struct default_header;
  879: 
  880: 				sapi_get_default_content_type_header(&default_header TSRMLS_CC);
  881: 				sapi_module.send_header(&default_header, SG(server_context) TSRMLS_CC);
  882: 				sapi_free_header(&default_header);
  883: 			}
  884: 			sapi_module.send_header(NULL, SG(server_context) TSRMLS_CC);
  885: 			ret = SUCCESS;
  886: 			break;
  887: 		case SAPI_HEADER_SEND_FAILED:
  888: 			SG(headers_sent) = 0;
  889: 			ret = FAILURE;
  890: 			break;
  891: 	}
  892: 
  893: 	sapi_send_headers_free(TSRMLS_C);
  894: 
  895: 	return ret;
  896: }
  897: 
  898: 
  899: SAPI_API int sapi_register_post_entries(sapi_post_entry *post_entries TSRMLS_DC)
  900: {
  901: 	sapi_post_entry *p=post_entries;
  902: 
  903: 	while (p->content_type) {
  904: 		if (sapi_register_post_entry(p TSRMLS_CC) == FAILURE) {
  905: 			return FAILURE;
  906: 		}
  907: 		p++;
  908: 	}
  909: 	return SUCCESS;
  910: }
  911: 
  912: 
  913: SAPI_API int sapi_register_post_entry(sapi_post_entry *post_entry TSRMLS_DC)
  914: {
  915: 	if (SG(sapi_started) && EG(in_execution)) {
  916: 		return FAILURE;
  917: 	}
  918: 	return zend_hash_add(&SG(known_post_content_types),
  919: 			post_entry->content_type, post_entry->content_type_len+1,
  920: 			(void *) post_entry, sizeof(sapi_post_entry), NULL);
  921: }
  922: 
  923: SAPI_API void sapi_unregister_post_entry(sapi_post_entry *post_entry TSRMLS_DC)
  924: {
  925: 	if (SG(sapi_started) && EG(in_execution)) {
  926: 		return;
  927: 	}
  928: 	zend_hash_del(&SG(known_post_content_types), post_entry->content_type,
  929: 			post_entry->content_type_len+1);
  930: }
  931: 
  932: 
  933: SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(TSRMLS_D) TSRMLS_DC)
  934: {
  935: 	if (SG(sapi_started) && EG(in_execution)) {
  936: 		return FAILURE;
  937: 	}
  938: 	sapi_module.default_post_reader = default_post_reader;
  939: 	return SUCCESS;
  940: }
  941: 
  942: 
  943: SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zval *destArray TSRMLS_DC) TSRMLS_DC)
  944: {
  945: 	if (SG(sapi_started) && EG(in_execution)) {
  946: 		return FAILURE;
  947: 	}
  948: 	sapi_module.treat_data = treat_data;
  949: 	return SUCCESS;
  950: }
  951: 
  952: SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC), unsigned int (*input_filter_init)(TSRMLS_D) TSRMLS_DC)
  953: {
  954: 	if (SG(sapi_started) && EG(in_execution)) {
  955: 		return FAILURE;
  956: 	}
  957: 	sapi_module.input_filter = input_filter;
  958: 	sapi_module.input_filter_init = input_filter_init;
  959: 	return SUCCESS;
  960: }
  961: 
  962: SAPI_API int sapi_flush(TSRMLS_D)
  963: {
  964: 	if (sapi_module.flush) {
  965: 		sapi_module.flush(SG(server_context));
  966: 		return SUCCESS;
  967: 	} else {
  968: 		return FAILURE;
  969: 	}
  970: }
  971: 
  972: SAPI_API struct stat *sapi_get_stat(TSRMLS_D)
  973: {
  974: 	if (sapi_module.get_stat) {
  975: 		return sapi_module.get_stat(TSRMLS_C);
  976: 	} else {
  977: 		if (!SG(request_info).path_translated || (VCWD_STAT(SG(request_info).path_translated, &SG(global_stat)) == -1)) {
  978: 			return NULL;
  979: 		}
  980: 		return &SG(global_stat);
  981: 	}
  982: }
  983: 
  984: SAPI_API char *sapi_getenv(char *name, size_t name_len TSRMLS_DC)
  985: {
  986: 	if (sapi_module.getenv) { 
  987: 		char *value, *tmp = sapi_module.getenv(name, name_len TSRMLS_CC);
  988: 		if (tmp) {
  989: 			value = estrdup(tmp);
  990: 		} else {
  991: 			return NULL;
  992: 		}
  993: 		sapi_module.input_filter(PARSE_ENV, name, &value, strlen(value), NULL TSRMLS_CC);
  994: 		return value;
  995: 	}
  996: 	return NULL;
  997: }
  998: 
  999: SAPI_API int sapi_get_fd(int *fd TSRMLS_DC)
 1000: {
 1001: 	if (sapi_module.get_fd) {
 1002: 		return sapi_module.get_fd(fd TSRMLS_CC);
 1003: 	} else {
 1004: 		return FAILURE;
 1005: 	}
 1006: }
 1007: 
 1008: SAPI_API int sapi_force_http_10(TSRMLS_D)
 1009: {
 1010: 	if (sapi_module.force_http_10) {
 1011: 		return sapi_module.force_http_10(TSRMLS_C);
 1012: 	} else {
 1013: 		return FAILURE;
 1014: 	}
 1015: }
 1016: 
 1017: 
 1018: SAPI_API int sapi_get_target_uid(uid_t *obj TSRMLS_DC)
 1019: {
 1020: 	if (sapi_module.get_target_uid) {
 1021: 		return sapi_module.get_target_uid(obj TSRMLS_CC);
 1022: 	} else {
 1023: 		return FAILURE;
 1024: 	}
 1025: }
 1026: 
 1027: SAPI_API int sapi_get_target_gid(gid_t *obj TSRMLS_DC)
 1028: {
 1029: 	if (sapi_module.get_target_gid) {
 1030: 		return sapi_module.get_target_gid(obj TSRMLS_CC);
 1031: 	} else {
 1032: 		return FAILURE;
 1033: 	}
 1034: }
 1035: 
 1036: SAPI_API double sapi_get_request_time(TSRMLS_D)
 1037: {
 1038: 	if(SG(global_request_time)) return SG(global_request_time);
 1039: 
 1040: 	if (sapi_module.get_request_time && SG(server_context)) {
 1041: 		SG(global_request_time) = sapi_module.get_request_time(TSRMLS_C);
 1042: 	} else {
 1043: 		struct timeval tp = {0};
 1044: 		if (!gettimeofday(&tp, NULL)) {
 1045: 			SG(global_request_time) = (double)(tp.tv_sec + tp.tv_usec / 1000000.00);
 1046: 		} else {
 1047: 			SG(global_request_time) = (double)time(0);
 1048: 		}
 1049: 	}
 1050: 	return SG(global_request_time);
 1051: }
 1052: 
 1053: SAPI_API void sapi_terminate_process(TSRMLS_D) {
 1054: 	if (sapi_module.terminate_process) {
 1055: 		sapi_module.terminate_process(TSRMLS_C);
 1056: 	}
 1057: }
 1058: 
 1059: /*
 1060:  * Local variables:
 1061:  * tab-width: 4
 1062:  * c-basic-offset: 4
 1063:  * End:
 1064:  * vim600: sw=4 ts=4 fdm=marker
 1065:  * vim<600: sw=4 ts=4
 1066:  */

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