File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / main / SAPI.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:48:05 2012 UTC (12 years, 4 months ago) by misho
Branches: php, MAIN
CVS tags: v5_3_10, HEAD
php

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

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