]> granicus.if.org Git - php/commitdiff
Reduced overhead of FastCGI using near-perfect hash function and predcalculated hash...
authorDmitry Stogov <dmitry@php.net>
Wed, 1 Sep 2010 15:34:48 +0000 (15:34 +0000)
committerDmitry Stogov <dmitry@php.net>
Wed, 1 Sep 2010 15:34:48 +0000 (15:34 +0000)
sapi/cgi/cgi_main.c
sapi/cgi/fastcgi.c
sapi/cgi/fastcgi.h

index 007e40ef104981ac01a43d3ad6a461f50ae594bd..5712d4ca5af689436366e98b36c85b4b02025436 100644 (file)
@@ -267,41 +267,30 @@ static void print_extensions(TSRMLS_D)
 #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 @@ static int sapi_cgibin_ub_write(const char *str, uint str_length TSRMLS_DC)
        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);
+
+       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 (fflush(stdout) == EOF) {
+               php_handle_aborted_connection();
+       }
+}
 
-static void sapi_cgibin_flush(void *server_context)
+static void sapi_fcgi_flush(void *server_context)
 {
-       if (fcgi_is_fastcgi()) {
-               fcgi_request *request = (fcgi_request*) server_context;
-               if (
+       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 @@ static int sapi_cgi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
 
        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 @@ static int sapi_cgi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
        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,7 +597,14 @@ static char *_sapi_cgibin_putenv(char *name, char *value TSRMLS_DC)
 
 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)
@@ -598,7 +618,7 @@ static void cgi_php_load_env_var(char *var, unsigned int var_len, char *val, uns
        }
 }
 
-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 @@ static void sapi_cgi_register_variables(zval *track_vars_array TSRMLS_DC)
 
        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 @@ static int sapi_cgi_activate(TSRMLS_D)
 
        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 @@ static int sapi_cgi_activate(TSRMLS_D)
 
                /* 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 @@ static int sapi_cgi_deactivate(TSRMLS_D)
                                php_handle_aborted_connection();
                        }
                } else {
-                       sapi_cgibin_flush(SG(server_context));
+                       sapi_cgi_flush(SG(server_context));
                }
        }
        return SUCCESS;
@@ -888,10 +946,10 @@ static sapi_module_struct cgi_sapi_module = {
        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 void php_cgi_usage(char *argv0)
  */
 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 (IS_SLASH(*(p-1)) &&
-                               (*(p+2) == 0 || IS_SLASH(*(p+2)))
-                       ) {
-                                       return 0;
+       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;
+                                       }                                                                                       
+                               }
                        }
                }
+               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 @@ static int is_valid_path(const char *path)
   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 @@ static void init_request_info(TSRMLS_D)
         * 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 @@ static void init_request_info(TSRMLS_D)
                        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 @@ static void init_request_info(TSRMLS_D)
                        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 @@ static void init_request_info(TSRMLS_D)
                                                        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 @@ static void init_request_info(TSRMLS_D)
                                                        }
                                                        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 @@ static void init_request_info(TSRMLS_D)
                                                        }
                                                        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 @@ static void init_request_info(TSRMLS_D)
                                         * 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 @@ static void init_request_info(TSRMLS_D)
                                        (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 @@ static void init_request_info(TSRMLS_D)
                        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 @@ consult the installation file that came with this distribution, or visit \n\
                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 @@ consult the installation file that came with this distribution, or visit \n\
 #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) {
index 74dd43d57d9f12c22373dd8755b15dd66074b3fd..4c60257e9b53da984b458fbbf70ffcb011616d3b 100644 (file)
@@ -142,11 +142,12 @@ static in_addr_t *allowed_clients = NULL;
 
 /* 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 @@ typedef struct _fcgi_hash {
        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 void fcgi_hash_clean(fcgi_hash *h)
 
 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 @@ static char* fcgi_hash_set(fcgi_hash *h, char *var, unsigned int var_len, char *
        }
        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 void fcgi_hash_del(fcgi_hash *h, char *var, unsigned int var_len)
        }
 }
 
-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 @@ fcgi_request *fcgi_init_request(int listen_socket)
        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 @@ static int fcgi_get_params(fcgi_request *req, unsigned char *p, unsigned char *e
                        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 @@ static int fcgi_read_request(fcgi_request *req)
                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,19 +1430,33 @@ char* fcgi_getenv(fcgi_request *req, const char* var, int var_len)
 
        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));
+       }
+}
+
+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));
        }
-       return NULL;
 }
 
 void fcgi_loadenv(fcgi_request *req, fcgi_apply_func func, zval *array TSRMLS_DC)
index fc9c88f495861022bdb3cf1a38beb1f40744c983..89aff7022c3e4a53f9686df10e535b9fdc4362dc 100644 (file)
 
 #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 @@ int fcgi_finish_request(fcgi_request *req, int force_close);
 
 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);