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

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