dmitry                                   Wed, 01 Sep 2010 15:34:48 +0000

Revision: http://svn.php.net/viewvc?view=revision&revision=302979

Log:
Reduced overhead of FastCGI using near-perfect hash function and predcalculated 
hash values.

Changed paths:
    U   php/php-src/trunk/sapi/cgi/cgi_main.c
    U   php/php-src/trunk/sapi/cgi/fastcgi.c
    U   php/php-src/trunk/sapi/cgi/fastcgi.h

Modified: php/php-src/trunk/sapi/cgi/cgi_main.c
===================================================================
--- php/php-src/trunk/sapi/cgi/cgi_main.c	2010-09-01 14:47:36 UTC (rev 302978)
+++ php/php-src/trunk/sapi/cgi/cgi_main.c	2010-09-01 15:34:48 UTC (rev 302979)
@@ -267,41 +267,30 @@
 #define STDOUT_FILENO 1
 #endif

-static inline size_t sapi_cgibin_single_write(const char *str, uint str_length TSRMLS_DC)
+static inline size_t sapi_cgi_single_write(const char *str, uint str_length TSRMLS_DC)
 {
 #ifdef PHP_WRITE_STDOUT
 	long ret;
-#else
-	size_t ret;
-#endif

-	if (fcgi_is_fastcgi()) {
-		fcgi_request *request = (fcgi_request*) SG(server_context);
-		long ret = fcgi_write(request, FCGI_STDOUT, str, str_length);
-		if (ret <= 0) {
-			return 0;
-		}
-		return ret;
-	}
-
-#ifdef PHP_WRITE_STDOUT
 	ret = write(STDOUT_FILENO, str, str_length);
 	if (ret <= 0) return 0;
 	return ret;
 #else
+	size_t ret;
+
 	ret = fwrite(str, 1, MIN(str_length, 16384), stdout);
 	return ret;
 #endif
 }

-static int sapi_cgibin_ub_write(const char *str, uint str_length TSRMLS_DC)
+static int sapi_cgi_ub_write(const char *str, uint str_length TSRMLS_DC)
 {
 	const char *ptr = str;
 	uint remaining = str_length;
 	size_t ret;

 	while (remaining > 0) {
-		ret = sapi_cgibin_single_write(ptr, remaining TSRMLS_CC);
+		ret = sapi_cgi_single_write(ptr, remaining TSRMLS_CC);
 		if (!ret) {
 			php_handle_aborted_connection();
 			return str_length - remaining;
@@ -313,21 +302,43 @@
 	return str_length;
 }

+static int sapi_fcgi_ub_write(const char *str, uint str_length TSRMLS_DC)
+{
+	const char *ptr = str;
+	uint remaining = str_length;
+	fcgi_request *request = (fcgi_request*) SG(server_context);

-static void sapi_cgibin_flush(void *server_context)
+	while (remaining > 0) {
+		long ret = fcgi_write(request, FCGI_STDOUT, ptr, remaining);
+
+		if (ret <= 0) {
+			php_handle_aborted_connection();
+			return str_length - remaining;
+		}
+		ptr += ret;
+		remaining -= ret;
+	}
+
+	return str_length;
+}
+
+static void sapi_cgi_flush(void *server_context)
 {
-	if (fcgi_is_fastcgi()) {
-		fcgi_request *request = (fcgi_request*) server_context;
-		if (
+	if (fflush(stdout) == EOF) {
+		php_handle_aborted_connection();
+	}
+}
+
+static void sapi_fcgi_flush(void *server_context)
+{
+	fcgi_request *request = (fcgi_request*) server_context;
+
+	if (
 #ifndef PHP_WIN32
 		!parent &&
 #endif
 		request && !fcgi_flush(request, 0)) {
-			php_handle_aborted_connection();
-		}
-		return;
-	}
-	if (fflush(stdout) == EOF) {
+
 		php_handle_aborted_connection();
 	}
 }
@@ -493,12 +504,24 @@

 	count_bytes = MIN(count_bytes, (uint) SG(request_info).content_length - SG(read_post_bytes));
 	while (read_bytes < count_bytes) {
-		if (fcgi_is_fastcgi()) {
-			fcgi_request *request = (fcgi_request*) SG(server_context);
-			tmp_read_bytes = fcgi_read(request, buffer + read_bytes, count_bytes - read_bytes);
-		} else {
-			tmp_read_bytes = read(STDIN_FILENO, buffer + read_bytes, count_bytes - read_bytes);
+		tmp_read_bytes = read(STDIN_FILENO, buffer + read_bytes, count_bytes - read_bytes);
+		if (tmp_read_bytes <= 0) {
+			break;
 		}
+		read_bytes += tmp_read_bytes;
+	}
+	return read_bytes;
+}
+
+static int sapi_fcgi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
+{
+	uint read_bytes = 0;
+	int tmp_read_bytes;
+	fcgi_request *request = (fcgi_request*) SG(server_context);
+
+	count_bytes = MIN(count_bytes, (uint) SG(request_info).content_length - SG(read_post_bytes));
+	while (read_bytes < count_bytes) {
+		tmp_read_bytes = fcgi_read(request, buffer + read_bytes, count_bytes - read_bytes);
 		if (tmp_read_bytes <= 0) {
 			break;
 		}
@@ -507,43 +530,33 @@
 	return read_bytes;
 }

-static char *sapi_cgibin_getenv(char *name, size_t name_len TSRMLS_DC)
+static char *sapi_cgi_getenv(char *name, size_t name_len TSRMLS_DC)
 {
+	return getenv(name);
+}
+
+static char *sapi_fcgi_getenv(char *name, size_t name_len TSRMLS_DC)
+{
 	/* when php is started by mod_fastcgi, no regular environment
 	 * is provided to PHP.  It is always sent to PHP at the start
 	 * of a request.  So we have to do our own lookup to get env
 	 * vars.  This could probably be faster somehow.  */
-	if (fcgi_is_fastcgi()) {
-		fcgi_request *request = (fcgi_request*) SG(server_context);
-		return fcgi_getenv(request, name, name_len);
-	}
+	fcgi_request *request = (fcgi_request*) SG(server_context);
+	char *ret = fcgi_getenv(request, name, name_len);
+
+	if (ret) return ret;
 	/*  if cgi, or fastcgi and not found in fcgi env
 		check the regular environment */
 	return getenv(name);
 }

-static char *_sapi_cgibin_putenv(char *name, char *value TSRMLS_DC)
+static char *_sapi_cgi_putenv(char *name, int name_len, char *value)
 {
-	int name_len;
 #if !HAVE_SETENV || !HAVE_UNSETENV
 	int len;
 	char *buf;
 #endif

-	if (!name) {
-		return NULL;
-	}
-	name_len = strlen(name);
-
-	/* when php is started by mod_fastcgi, no regular environment
-	 * is provided to PHP.  It is always sent to PHP at the start
-	 * of a request.  So we have to do our own lookup to get env
-	 * vars.  This could probably be faster somehow.  */
-	if (fcgi_is_fastcgi()) {
-		fcgi_request *request = (fcgi_request*) SG(server_context);
-		return fcgi_putenv(request, name, name_len, value);
-	}
-
 #if HAVE_SETENV
 	if (value) {
 		setenv(name, value, 1);
@@ -584,9 +597,16 @@

 static char *sapi_cgi_read_cookies(TSRMLS_D)
 {
-	return sapi_cgibin_getenv((char *) "HTTP_COOKIE", sizeof("HTTP_COOKIE")-1 TSRMLS_CC);
+	return getenv("HTTP_COOKIE");
 }

+static char *sapi_fcgi_read_cookies(TSRMLS_D)
+{
+	fcgi_request *request = (fcgi_request*) SG(server_context);
+
+	return FCGI_GETENV(request, "HTTP_COOKIE");
+}
+
 static void cgi_php_load_env_var(char *var, unsigned int var_len, char *val, unsigned int val_len, void *arg TSRMLS_DC)
 {
 	zval *array_ptr = (zval*)arg;
@@ -598,7 +618,7 @@
 	}
 }

-void cgi_php_import_environment_variables(zval *array_ptr TSRMLS_DC)
+static void cgi_php_import_environment_variables(zval *array_ptr TSRMLS_DC)
 {
 	if (PG(http_globals)[TRACK_VARS_ENV] &&
 		array_ptr != PG(http_globals)[TRACK_VARS_ENV] &&
@@ -648,25 +668,51 @@

 	if (CGIG(fix_pathinfo)) {
 		char *script_name = SG(request_info).request_uri;
-		unsigned int script_name_len = script_name ? strlen(script_name) : 0;
-		char *path_info = sapi_cgibin_getenv("PATH_INFO", sizeof("PATH_INFO")-1 TSRMLS_CC);
-		unsigned int path_info_len = path_info ? strlen(path_info) : 0;
+		char *path_info;
+		unsigned int path_info_len;
+		int free_php_self;
+		ALLOCA_FLAG(use_heap)

-		php_self_len = script_name_len + path_info_len;
-		php_self = emalloc(php_self_len + 1);
+		if (fcgi_is_fastcgi()) {
+			fcgi_request *request = (fcgi_request*) SG(server_context);

-		if (script_name) {
-			memcpy(php_self, script_name, script_name_len + 1);
+			path_info = FCGI_GETENV(request, "PATH_INFO");
+		} else {
+			path_info = getenv("PATH_INFO");
 		}
+
 		if (path_info) {
-			memcpy(php_self + script_name_len, path_info, path_info_len + 1);
+			unsigned int path_info_len = strlen(path_info);
+
+			if (script_name) {
+				unsigned int script_name_len = strlen(script_name);
+
+				php_self_len = script_name_len + path_info_len;
+				php_self = do_alloca(php_self_len + 1, use_heap);
+				memcpy(php_self, script_name, script_name_len + 1);
+				memcpy(php_self + script_name_len, path_info, path_info_len + 1);
+				free_php_self = 1;
+			}  else {
+				php_self = path_info;
+				free_php_self = 0;
+			}
+		} else if (script_name) {
+			php_self = script_name;
+			php_self_len = strlen(script_name);
+			free_php_self = 0;
+		} else {
+			php_self = "";
+			php_self_len = 0;
+			free_php_self = 0;
 		}

 		/* Build the special-case PHP_SELF variable for the CGI version */
 		if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &php_self, php_self_len, &php_self_len TSRMLS_CC)) {
 			php_register_variable_safe("PHP_SELF", php_self, php_self_len, track_vars_array TSRMLS_CC);
 		}
-		efree(php_self);
+		if (free_php_self) {
+			free_alloca(php_self, use_heap);
+		}
 	} else {
 		php_self = SG(request_info).request_uri ? SG(request_info).request_uri : "";
 		php_self_len = strlen(php_self);
@@ -787,7 +833,13 @@

 	if (php_ini_has_per_host_config()) {
 		/* Activate per-host-system-configuration defined in php.ini and stored into configuration_hash during startup */
-		server_name = sapi_cgibin_getenv("SERVER_NAME", sizeof("SERVER_NAME") - 1 TSRMLS_CC);
+		if (fcgi_is_fastcgi()) {
+			fcgi_request *request = (fcgi_request*) SG(server_context);
+
+			server_name = FCGI_GETENV(request, "SERVER_NAME");
+		} else {
+			server_name = getenv("SERVER_NAME");
+		}
 		/* SERVER_NAME should also be defined at this stage..but better check it anyway */
 		if (server_name) {
 			server_name_len = strlen(server_name);
@@ -821,7 +873,13 @@

 		/* Load and activate user ini files in path starting from DOCUMENT_ROOT */
 		if (PG(user_ini_filename) && *PG(user_ini_filename)) {
-			doc_root = sapi_cgibin_getenv("DOCUMENT_ROOT", sizeof("DOCUMENT_ROOT") - 1 TSRMLS_CC);
+			if (fcgi_is_fastcgi()) {
+				fcgi_request *request = (fcgi_request*) SG(server_context);
+
+				doc_root = FCGI_GETENV(request, "DOCUMENT_ROOT");
+			} else {
+				doc_root = getenv("DOCUMENT_ROOT");
+			}
 			/* DOCUMENT_ROOT should also be defined at this stage..but better check it anyway */
 			if (doc_root) {
 				doc_root_len = strlen(doc_root);
@@ -862,7 +920,7 @@
 				php_handle_aborted_connection();
 			}
 		} else {
-			sapi_cgibin_flush(SG(server_context));
+			sapi_cgi_flush(SG(server_context));
 		}
 	}
 	return SUCCESS;
@@ -888,10 +946,10 @@
 	sapi_cgi_activate,				/* activate */
 	sapi_cgi_deactivate,			/* deactivate */

-	sapi_cgibin_ub_write,			/* unbuffered write */
-	sapi_cgibin_flush,				/* flush */
+	sapi_cgi_ub_write,				/* unbuffered write */
+	sapi_cgi_flush,					/* flush */
 	NULL,							/* get uid */
-	sapi_cgibin_getenv,				/* getenv */
+	sapi_cgi_getenv,				/* getenv */

 	php_error,						/* error handler */

@@ -966,34 +1024,43 @@
  */
 static int is_valid_path(const char *path)
 {
-	const char *p;
+	const char *p = path;

-	if (!path) {
+	if (UNEXPECTED(!p)) {
 		return 0;
 	}
-	p = strstr(path, "..");
-	if (p) {
-		if ((p == path || IS_SLASH(*(p-1))) &&
-			(*(p+2) == 0 || IS_SLASH(*(p+2)))
-		) {
-			return 0;
-		}
-		while (1) {
-			p = strstr(p+1, "..");
-			if (!p) {
-				break;
+	if (UNEXPECTED(*p == '.') && *(p+1) == '.' && (!*(p+2) || IS_SLASH(*(p+2)))) {
+		return 0;
+	}
+	while (*p) {
+		if (IS_SLASH(*p)) {
+			p++;
+			if (UNEXPECTED(*p == '.')) {
+				p++;
+				if (UNEXPECTED(*p == '.')) {
+					p++;
+					if (UNEXPECTED(!*p) || UNEXPECTED(IS_SLASH(*p))) {
+						return 0;
+					}
+				}
 			}
-			if (IS_SLASH(*(p-1)) &&
-				(*(p+2) == 0 || IS_SLASH(*(p+2)))
-			) {
-					return 0;
-			}
 		}
+		p++;
 	}
 	return 1;
 }
 /* }}} */

+#define CGI_GETENV(name) \
+	((request) ? \
+		FCGI_GETENV(request, name) : \
+    	getenv(name))
+
+#define CGI_PUTENV(name, value) \
+	((request) ? \
+		FCGI_PUTENV(request, name, value) : \
+		_sapi_cgi_putenv(name, sizeof(name)-1, value))
+
 /* {{{ init_request_info

   initializes request_info structure
@@ -1060,10 +1127,10 @@
   Comments in the code below refer to using the above URL in a request

  */
-static void init_request_info(TSRMLS_D)
+static void init_request_info(fcgi_request *request TSRMLS_DC)
 {
-	char *env_script_filename = sapi_cgibin_getenv("SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME")-1 TSRMLS_CC);
-	char *env_path_translated = sapi_cgibin_getenv("PATH_TRANSLATED", sizeof("PATH_TRANSLATED")-1 TSRMLS_CC);
+	char *env_script_filename = CGI_GETENV("SCRIPT_FILENAME");
+	char *env_path_translated = CGI_GETENV("PATH_TRANSLATED");
 	char *script_path_translated = env_script_filename;

 	/* some broken servers do not have script_filename or argv0
@@ -1089,14 +1156,14 @@
 	 * of the script will be retreived later via argc/argv */
 	if (script_path_translated) {
 		const char *auth;
-		char *content_length = sapi_cgibin_getenv("CONTENT_LENGTH", sizeof("CONTENT_LENGTH")-1 TSRMLS_CC);
-		char *content_type = sapi_cgibin_getenv("CONTENT_TYPE", sizeof("CONTENT_TYPE")-1 TSRMLS_CC);
-		char *env_path_info = sapi_cgibin_getenv("PATH_INFO", sizeof("PATH_INFO")-1 TSRMLS_CC);
-		char *env_script_name = sapi_cgibin_getenv("SCRIPT_NAME", sizeof("SCRIPT_NAME")-1 TSRMLS_CC);
+		char *content_length = CGI_GETENV("CONTENT_LENGTH");
+		char *content_type = CGI_GETENV("CONTENT_TYPE");
+		char *env_path_info = CGI_GETENV("PATH_INFO");
+		char *env_script_name = CGI_GETENV("SCRIPT_NAME");

 #ifdef PHP_WIN32
 		/* Hack for buggy IIS that sets incorrect PATH_INFO */
-		char *env_server_software = sapi_cgibin_getenv("SERVER_SOFTWARE", sizeof("SERVER_SOFTWARE")-1 TSRMLS_CC);
+		char *env_server_software = CGI_GETENV("SERVER_SOFTWARE");

 		if (env_server_software &&
 			env_script_name &&
@@ -1104,20 +1171,20 @@
 			strncmp(env_server_software, "Microsoft-IIS", sizeof("Microsoft-IIS")-1) == 0 &&
 			strncmp(env_path_info, env_script_name, strlen(env_script_name)) == 0
 		) {
-			env_path_info = _sapi_cgibin_putenv("ORIG_PATH_INFO", env_path_info TSRMLS_CC);
+			env_path_info = CGI_PUTENV("ORIG_PATH_INFO", env_path_info);
 			env_path_info += strlen(env_script_name);
 			if (*env_path_info == 0) {
 				env_path_info = NULL;
 			}
-			env_path_info = _sapi_cgibin_putenv("PATH_INFO", env_path_info TSRMLS_CC);
+			env_path_info = CGI_PUTENV("PATH_INFO", env_path_info);
 		}
 #endif

 		if (CGIG(fix_pathinfo)) {
 			struct stat st;
 			char *real_path = NULL;
-			char *env_redirect_url = sapi_cgibin_getenv("REDIRECT_URL", sizeof("REDIRECT_URL")-1 TSRMLS_CC);
-			char *env_document_root = sapi_cgibin_getenv("DOCUMENT_ROOT", sizeof("DOCUMENT_ROOT")-1 TSRMLS_CC);
+			char *env_redirect_url = CGI_GETENV("REDIRECT_URL");
+			char *env_document_root = CGI_GETENV("DOCUMENT_ROOT");
 			char *orig_path_translated = env_path_translated;
 			char *orig_path_info = env_path_info;
 			char *orig_script_name = env_script_name;
@@ -1125,7 +1192,7 @@
 			int script_path_translated_len;

 			if (!env_document_root && PG(doc_root)) {
-				env_document_root = _sapi_cgibin_putenv("DOCUMENT_ROOT", PG(doc_root) TSRMLS_CC);
+				env_document_root = CGI_PUTENV("DOCUMENT_ROOT", PG(doc_root));
 				/* fix docroot */
 				TRANSLATE_SLASHES(env_document_root);
 			}
@@ -1192,28 +1259,28 @@
 							if (orig_path_info) {
 								char old;

-								_sapi_cgibin_putenv("ORIG_PATH_INFO", orig_path_info TSRMLS_CC);
+								CGI_PUTENV("ORIG_PATH_INFO", orig_path_info);
 								old = path_info[0];
 								path_info[0] = 0;
 								if (!orig_script_name ||
 									strcmp(orig_script_name, env_path_info) != 0) {
 									if (orig_script_name) {
-										_sapi_cgibin_putenv("ORIG_SCRIPT_NAME", orig_script_name TSRMLS_CC);
+										CGI_PUTENV("ORIG_SCRIPT_NAME", orig_script_name);
 									}
-									SG(request_info).request_uri = _sapi_cgibin_putenv("SCRIPT_NAME", env_path_info TSRMLS_CC);
+									SG(request_info).request_uri = CGI_PUTENV("SCRIPT_NAME", env_path_info);
 								} else {
 									SG(request_info).request_uri = orig_script_name;
 								}
 								path_info[0] = old;
 							}
-							env_path_info = _sapi_cgibin_putenv("PATH_INFO", path_info TSRMLS_CC);
+							env_path_info = CGI_PUTENV("PATH_INFO", path_info);
 						}
 						if (!orig_script_filename ||
 							strcmp(orig_script_filename, pt) != 0) {
 							if (orig_script_filename) {
-								_sapi_cgibin_putenv("ORIG_SCRIPT_FILENAME", orig_script_filename TSRMLS_CC);
+								CGI_PUTENV("ORIG_SCRIPT_FILENAME", orig_script_filename);
 							}
-							script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", pt TSRMLS_CC);
+							script_path_translated = CGI_PUTENV("SCRIPT_FILENAME", pt);
 						}
 						TRANSLATE_SLASHES(pt);

@@ -1243,9 +1310,9 @@
 							}
 							path_translated[path_translated_len] = '\0';
 							if (orig_path_translated) {
-								_sapi_cgibin_putenv("ORIG_PATH_TRANSLATED", orig_path_translated TSRMLS_CC);
+								CGI_PUTENV("ORIG_PATH_TRANSLATED", orig_path_translated);
 							}
-							env_path_translated = _sapi_cgibin_putenv("PATH_TRANSLATED", path_translated TSRMLS_CC);
+							env_path_translated = CGI_PUTENV("PATH_TRANSLATED", path_translated);
 							efree(path_translated);
 						} else if (	env_script_name &&
 									strstr(pt, env_script_name)
@@ -1262,9 +1329,9 @@
 							}
 							path_translated[path_translated_len] = '\0';
 							if (orig_path_translated) {
-								_sapi_cgibin_putenv("ORIG_PATH_TRANSLATED", orig_path_translated TSRMLS_CC);
+								CGI_PUTENV("ORIG_PATH_TRANSLATED", orig_path_translated);
 							}
-							env_path_translated = _sapi_cgibin_putenv("PATH_TRANSLATED", path_translated TSRMLS_CC);
+							env_path_translated = CGI_PUTENV("PATH_TRANSLATED", path_translated);
 							efree(path_translated);
 						}
 						break;
@@ -1277,18 +1344,18 @@
 					 * have failed anyway... we output 'no input file' now.
 					 */
 					if (orig_script_filename) {
-						_sapi_cgibin_putenv("ORIG_SCRIPT_FILENAME", orig_script_filename TSRMLS_CC);
+						CGI_PUTENV("ORIG_SCRIPT_FILENAME", orig_script_filename);
 					}
-					script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", NULL TSRMLS_CC);
+					script_path_translated = CGI_PUTENV("SCRIPT_FILENAME", NULL);
 					SG(sapi_headers).http_response_code = 404;
 				}
 				if (!SG(request_info).request_uri) {
 					if (!orig_script_name ||
 						strcmp(orig_script_name, env_script_name) != 0) {
 						if (orig_script_name) {
-							_sapi_cgibin_putenv("ORIG_SCRIPT_NAME", orig_script_name TSRMLS_CC);
+							CGI_PUTENV("ORIG_SCRIPT_NAME", orig_script_name);
 						}
-						SG(request_info).request_uri = _sapi_cgibin_putenv("SCRIPT_NAME", env_script_name TSRMLS_CC);
+						SG(request_info).request_uri = CGI_PUTENV("SCRIPT_NAME", env_script_name);
 					} else {
 						SG(request_info).request_uri = orig_script_name;
 					}
@@ -1302,25 +1369,25 @@
 					(script_path_translated != orig_script_filename &&
 					strcmp(script_path_translated, orig_script_filename) != 0)) {
 					if (orig_script_filename) {
-						_sapi_cgibin_putenv("ORIG_SCRIPT_FILENAME", orig_script_filename TSRMLS_CC);
+						CGI_PUTENV("ORIG_SCRIPT_FILENAME", orig_script_filename);
 					}
-					script_path_translated = _sapi_cgibin_putenv("SCRIPT_FILENAME", script_path_translated TSRMLS_CC);
+					script_path_translated = CGI_PUTENV("SCRIPT_FILENAME", script_path_translated);
 				}
 				if (env_redirect_url) {
 					if (orig_path_info) {
-						_sapi_cgibin_putenv("ORIG_PATH_INFO", orig_path_info TSRMLS_CC);
-						_sapi_cgibin_putenv("PATH_INFO", NULL TSRMLS_CC);
+						CGI_PUTENV("ORIG_PATH_INFO", orig_path_info);
+						CGI_PUTENV("PATH_INFO", NULL);
 					}
 					if (orig_path_translated) {
-						_sapi_cgibin_putenv("ORIG_PATH_TRANSLATED", orig_path_translated TSRMLS_CC);
-						_sapi_cgibin_putenv("PATH_TRANSLATED", NULL TSRMLS_CC);
+						CGI_PUTENV("ORIG_PATH_TRANSLATED", orig_path_translated);
+						CGI_PUTENV("PATH_TRANSLATED", NULL);
 					}
 				}
 				if (env_script_name != orig_script_name) {
 					if (orig_script_name) {
-						_sapi_cgibin_putenv("ORIG_SCRIPT_NAME", orig_script_name TSRMLS_CC);
+						CGI_PUTENV("ORIG_SCRIPT_NAME", orig_script_name);
 					}
-					SG(request_info).request_uri = _sapi_cgibin_putenv("SCRIPT_NAME", env_script_name TSRMLS_CC);
+					SG(request_info).request_uri = CGI_PUTENV("SCRIPT_NAME", env_script_name);
 				} else {
 					SG(request_info).request_uri = env_script_name;
 				}
@@ -1342,14 +1409,14 @@
 			SG(request_info).path_translated = estrdup(script_path_translated);
 		}

-		SG(request_info).request_method = sapi_cgibin_getenv("REQUEST_METHOD", sizeof("REQUEST_METHOD")-1 TSRMLS_CC);
+		SG(request_info).request_method = CGI_GETENV("REQUEST_METHOD");
 		/* FIXME - Work out proto_num here */
-		SG(request_info).query_string = sapi_cgibin_getenv("QUERY_STRING", sizeof("QUERY_STRING")-1 TSRMLS_CC);
+		SG(request_info).query_string = CGI_GETENV("QUERY_STRING");
 		SG(request_info).content_type = (content_type ? content_type : "" );
 		SG(request_info).content_length = (content_length ? atoi(content_length) : 0);

 		/* The CGI RFC allows servers to pass on unvalidated Authorization data */
-		auth = sapi_cgibin_getenv("HTTP_AUTHORIZATION", sizeof("HTTP_AUTHORIZATION")-1 TSRMLS_CC);
+		auth = CGI_GETENV("HTTP_AUTHORIZATION");
 		php_handle_auth_data(auth TSRMLS_CC);
 	}
 }
@@ -1867,6 +1934,13 @@
 		fastcgi = fcgi_is_fastcgi();
 	}
 	if (fastcgi) {
+		/* Override SAPI callbacks */
+		sapi_module.ub_write     = sapi_fcgi_ub_write;
+		sapi_module.flush        = sapi_fcgi_flush;
+		sapi_module.read_post    = sapi_fcgi_read_post;
+		sapi_module.getenv       = sapi_fcgi_getenv;
+		sapi_module.read_cookies = sapi_fcgi_read_cookies;
+
 		/* How many times to run PHP scripts before dying */
 		if (getenv("PHP_FCGI_MAX_REQUESTS")) {
 			max_requests = atoi(getenv("PHP_FCGI_MAX_REQUESTS"));
@@ -2028,7 +2102,7 @@
 #endif
 		while (!fastcgi || fcgi_accept_request(request) >= 0) {
 			SG(server_context) = fastcgi ? (void *) request : (void *) 1;
-			init_request_info(TSRMLS_C);
+			init_request_info(request TSRMLS_CC);
 			CG(interactive) = 0;

 			if (!cgi && !fastcgi) {

Modified: php/php-src/trunk/sapi/cgi/fastcgi.c
===================================================================
--- php/php-src/trunk/sapi/cgi/fastcgi.c	2010-09-01 14:47:36 UTC (rev 302978)
+++ php/php-src/trunk/sapi/cgi/fastcgi.c	2010-09-01 15:34:48 UTC (rev 302979)
@@ -142,11 +142,12 @@

 /* hash table */

-#define FCGI_HASH_TABLE_SIZE 64
+#define FCGI_HASH_TABLE_SIZE 128
 #define FCGI_HASH_TABLE_MASK (FCGI_HASH_TABLE_SIZE - 1)
+#define FCGI_HASH_SEG_SIZE   4096

 typedef struct _fcgi_hash_bucket {
-	unsigned long             hash_value;
+	unsigned int              hash_value;
 	unsigned int              var_len;
 	char                     *var;
 	unsigned int              val_len;
@@ -175,16 +176,16 @@
 	fcgi_data_seg     *data;
 } fcgi_hash;

-static void fcgi_hash_init(fcgi_hash *h, unsigned int seg_size)
+static void fcgi_hash_init(fcgi_hash *h)
 {
 	memset(h->hash_table, 0, sizeof(h->hash_table));
 	h->list = NULL;
 	h->buckets = (fcgi_hash_buckets*)malloc(sizeof(fcgi_hash_buckets));
 	h->buckets->idx = 0;
 	h->buckets->next = NULL;
-	h->data = (fcgi_data_seg*)malloc(sizeof(fcgi_data_seg) - 1 + seg_size);
+	h->data = (fcgi_data_seg*)malloc(sizeof(fcgi_data_seg) - 1 + FCGI_HASH_SEG_SIZE);
 	h->data->pos = h->data->data;
-	h->data->end = h->data->pos + seg_size;
+	h->data->end = h->data->pos + FCGI_HASH_SEG_SIZE;
 	h->data->next = NULL;
 }

@@ -231,29 +232,31 @@

 static inline char* fcgi_hash_strndup(fcgi_hash *h, char *str, unsigned int str_len)
 {
+	char *ret;
+
 	if (UNEXPECTED(h->data->pos + str_len + 1 >= h->data->end)) {
-		fcgi_data_seg *p = (fcgi_data_seg*)malloc(sizeof(fcgi_data_seg) + str_len);
+		unsigned int seg_size = (str_len + 1 > FCGI_HASH_SEG_SIZE) ? str_len + 1 : FCGI_HASH_SEG_SIZE;
+		fcgi_data_seg *p = (fcgi_data_seg*)malloc(sizeof(fcgi_data_seg) - 1 + seg_size);

 		p->pos = p->data;
-		p->end = p->pos + str_len + 1;
+		p->end = p->pos + seg_size;
 		p->next = h->data;
 		h->data = p;
 	}
-	memcpy(h->data->pos, str, str_len);
-	str = h->data->pos;
-	h->data->pos[str_len] = 0;
+	ret = h->data->pos;
+	memcpy(ret, str, str_len);
+	ret[str_len] = 0;
 	h->data->pos += str_len + 1;
-	return str;
+	return ret;
 }

-static char* fcgi_hash_set(fcgi_hash *h, char *var, unsigned int var_len, char *val, unsigned int val_len)
+static char* fcgi_hash_set(fcgi_hash *h, unsigned int hash_value, char *var, unsigned int var_len, char *val, unsigned int val_len)
 {
-	unsigned long     hash_value = zend_inline_hash_func(var, var_len);
 	unsigned int      idx = hash_value & FCGI_HASH_TABLE_MASK;
 	fcgi_hash_bucket *p = h->hash_table[idx];

-	while (p != NULL) {
-		if (p->hash_value == hash_value &&
+	while (UNEXPECTED(p != NULL)) {
+		if (UNEXPECTED(p->hash_value == hash_value) &&
 		    p->var_len == var_len &&
 		    memcmp(p->var, var, var_len) == 0) {

@@ -272,21 +275,20 @@
 	}
 	p = h->buckets->data + h->buckets->idx;
 	h->buckets->idx++;
+	p->next = h->hash_table[idx];
+	h->hash_table[idx] = p;
+	p->list_next = h->list;
+	h->list = p;
 	p->hash_value = hash_value;
 	p->var_len = var_len;
 	p->var = fcgi_hash_strndup(h, var, var_len);
 	p->val_len = val_len;
 	p->val = fcgi_hash_strndup(h, val, val_len);
-	p->next = h->hash_table[idx];
-	h->hash_table[idx] = p;
-	p->list_next = h->list;
-	h->list = p;
 	return p->val;
 }

-static void fcgi_hash_del(fcgi_hash *h, char *var, unsigned int var_len)
+static void fcgi_hash_del(fcgi_hash *h, unsigned int hash_value, char *var, unsigned int var_len)
 {
-	unsigned long     hash_value = zend_inline_hash_func(var, var_len);
 	unsigned int      idx = hash_value & FCGI_HASH_TABLE_MASK;
 	fcgi_hash_bucket **p = &h->hash_table[idx];

@@ -304,9 +306,8 @@
 	}
 }

-static char *fcgi_hash_get(fcgi_hash *h, char *var, unsigned int var_len, unsigned int *val_len)
+static char *fcgi_hash_get(fcgi_hash *h, unsigned int hash_value, char *var, unsigned int var_len, unsigned int *val_len)
 {
-	unsigned long     hash_value = zend_inline_hash_func(var, var_len);
 	unsigned int      idx = hash_value & FCGI_HASH_TABLE_MASK;
 	fcgi_hash_bucket *p = h->hash_table[idx];

@@ -745,7 +746,7 @@
 	req->tcp = !GetNamedPipeInfo((HANDLE)_get_osfhandle(req->listen_socket), NULL, NULL, NULL, NULL);
 #endif

-	fcgi_hash_init(&req->env, 4096);
+	fcgi_hash_init(&req->env);

 	return req;
 }
@@ -858,7 +859,7 @@
 			ret = 0;
 			break;
 		}
-		fcgi_hash_set(&req->env, (char*)p, name_len, (char*)p + name_len, val_len);
+		fcgi_hash_set(&req->env, FCGI_HASH_FUNC(p, name_len), (char*)p, name_len, (char*)p + name_len, val_len);
 		p += name_len + val_len;
 	}
 	return ret;
@@ -909,13 +910,13 @@
 		req->keep = (((fcgi_begin_request*)buf)->flags & FCGI_KEEP_CONN);
 		switch ((((fcgi_begin_request*)buf)->roleB1 << 8) + ((fcgi_begin_request*)buf)->roleB0) {
 			case FCGI_RESPONDER:
-				fcgi_hash_set(&req->env, "FCGI_ROLE", sizeof("FCGI_ROLE")-1, "RESPONDER", sizeof("RESPONDER")-1);
+				fcgi_hash_set(&req->env, FCGI_HASH_FUNC("FCGI_ROLE", sizeof("FCGI_ROLE")-1), "FCGI_ROLE", sizeof("FCGI_ROLE")-1, "RESPONDER", sizeof("RESPONDER")-1);
 				break;
 			case FCGI_AUTHORIZER:
-				fcgi_hash_set(&req->env, "FCGI_ROLE", sizeof("FCGI_ROLE")-1, "AUTHORIZER", sizeof("AUTHORIZER")-1);
+				fcgi_hash_set(&req->env, FCGI_HASH_FUNC("FCGI_ROLE", sizeof("FCGI_ROLE")-1), "FCGI_ROLE", sizeof("FCGI_ROLE")-1, "AUTHORIZER", sizeof("AUTHORIZER")-1);
 				break;
 			case FCGI_FILTER:
-				fcgi_hash_set(&req->env, "FCGI_ROLE", sizeof("FCGI_ROLE")-1, "FILTER", sizeof("FILTER")-1);
+				fcgi_hash_set(&req->env, FCGI_HASH_FUNC("FCGI_ROLE", sizeof("FCGI_ROLE")-1), "FCGI_ROLE", sizeof("FCGI_ROLE")-1, "FILTER", sizeof("FILTER")-1);
 				break;
 			default:
 				return 0;
@@ -1429,21 +1430,35 @@

 	if (!req) return NULL;

-	return fcgi_hash_get(&req->env, (char*)var, var_len, &val_len);
+	return fcgi_hash_get(&req->env, FCGI_HASH_FUNC(var, var_len), (char*)var, var_len, &val_len);
 }

+char* fcgi_quick_getenv(fcgi_request *req, const char* var, int var_len, unsigned int hash_value)
+{
+	unsigned int val_len;
+
+	return fcgi_hash_get(&req->env, hash_value, (char*)var, var_len, &val_len);
+}
+
 char* fcgi_putenv(fcgi_request *req, char* var, int var_len, char* val)
 {
-	if (var && req) {
-		if (val == NULL) {
-			fcgi_hash_del(&req->env, var, var_len);
-		} else {
-			return fcgi_hash_set(&req->env, var, var_len, val, strlen(val));
-		}
+	if (!req) return NULL;
+	if (val == NULL) {
+		fcgi_hash_del(&req->env, FCGI_HASH_FUNC(var, var_len), var, var_len);
+	} else {
+		return fcgi_hash_set(&req->env, FCGI_HASH_FUNC(var, var_len), var, var_len, val, strlen(val));
 	}
-	return NULL;
 }

+char* fcgi_quick_putenv(fcgi_request *req, char* var, int var_len, unsigned int hash_value, char* val)
+{
+	if (val == NULL) {
+		fcgi_hash_del(&req->env, hash_value, var, var_len);
+	} else {
+		return fcgi_hash_set(&req->env, hash_value, var, var_len, val, strlen(val));
+	}
+}
+
 void fcgi_loadenv(fcgi_request *req, fcgi_apply_func func, zval *array TSRMLS_DC)
 {
 	fcgi_hash_apply(&req->env, func, array TSRMLS_CC);

Modified: php/php-src/trunk/sapi/cgi/fastcgi.h
===================================================================
--- php/php-src/trunk/sapi/cgi/fastcgi.h	2010-09-01 14:47:36 UTC (rev 302978)
+++ php/php-src/trunk/sapi/cgi/fastcgi.h	2010-09-01 15:34:48 UTC (rev 302979)
@@ -26,6 +26,23 @@

 #define FCGI_KEEP_CONN  1

+/* this is near the perfect hash function for most useful FastCGI variables
+ * which combines efficiency and minimal hash collisions
+ */
+
+#define FCGI_HASH_FUNC(var, var_len) \
+	(UNEXPECTED(var_len < 3) ? var_len : \
+		(((unsigned int)var[3]) << 2) + \
+		(((unsigned int)var[var_len-2]) << 4) + \
+		(((unsigned int)var[var_len-1]) << 2) + \
+		var_len)
+
+#define FCGI_GETENV(request, name) \
+	fcgi_quick_getenv(request, name, sizeof(name)-1, FCGI_HASH_FUNC(name, sizeof(name)-1))
+
+#define FCGI_PUTENV(request, name, value) \
+	fcgi_quick_putenv(request, name, sizeof(name)-1, FCGI_HASH_FUNC(name, sizeof(name)-1), value)
+
 typedef enum _fcgi_role {
 	FCGI_RESPONDER	= 1,
 	FCGI_AUTHORIZER	= 2,
@@ -108,6 +125,8 @@

 char* fcgi_getenv(fcgi_request *req, const char* var, int var_len);
 char* fcgi_putenv(fcgi_request *req, char* var, int var_len, char* val);
+char* fcgi_quick_getenv(fcgi_request *req, const char* var, int var_len, unsigned int hash_value);
+char* fcgi_quick_putenv(fcgi_request *req, char* var, int var_len, unsigned int hash_value, char* val);
 void  fcgi_loadenv(fcgi_request *req, fcgi_apply_func load_func, zval *array TSRMLS_DC);

 int fcgi_read(fcgi_request *req, char *str, int len);
-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to