]> granicus.if.org Git - php/commitdiff
improved performance of FastCGI request parsing
authorDmitry Stogov <dmitry@php.net>
Wed, 18 Aug 2010 08:22:41 +0000 (08:22 +0000)
committerDmitry Stogov <dmitry@php.net>
Wed, 18 Aug 2010 08:22:41 +0000 (08:22 +0000)
NEWS
sapi/cgi/cgi_main.c
sapi/cgi/fastcgi.c
sapi/cgi/fastcgi.h

diff --git a/NEWS b/NEWS
index 44f8d362c543f9c9a6a0253ab526d91685a4305a..3d5454f9f2be643b4ab7ef24bf4e44b1af364243 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -25,6 +25,7 @@
   . ZEND_FETCH_*_R operations simplified and can't be used with EXT_TYPE_UNUSED
     flag any more. Thit is very rare and useless case. ZEND_FREE might be
     required after them instead.
+  . improved performance of FastCGI request parsing
 - Added concept of interned strings. All strings constants known at compile
   time are allocated in a single copy and never changed. (Dmitry)
 - Added an optimization which saves memory and emalloc/efree calls for empty
index 81ae211939094c58c5daebbd789779c7632d5ace..4286de5d4ca0e2d0fbe71269087d4f1c877ccb4d 100644 (file)
@@ -587,6 +587,17 @@ static char *sapi_cgi_read_cookies(TSRMLS_D)
        return sapi_cgibin_getenv((char *) "HTTP_COOKIE", sizeof("HTTP_COOKIE")-1 TSRMLS_CC);
 }
 
+static void cgi_php_load_env_var(char *var, unsigned int var_len, char *val, unsigned int val_len, void *arg)
+{
+       zval *array_ptr = (zval*)arg;   
+       int filter_arg = (array_ptr == PG(http_globals)[TRACK_VARS_ENV])?PARSE_ENV:PARSE_SERVER;
+       unsigned int new_val_len;
+
+       if (sapi_module.input_filter(filter_arg, var, &val, strlen(val), &new_val_len TSRMLS_CC)) {
+               php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC);
+       }
+}
+
 void cgi_php_import_environment_variables(zval *array_ptr TSRMLS_DC)
 {
        if (PG(http_globals)[TRACK_VARS_ENV] &&
@@ -616,26 +627,11 @@ void cgi_php_import_environment_variables(zval *array_ptr TSRMLS_DC)
 
        if (fcgi_is_fastcgi()) {
                fcgi_request *request = (fcgi_request*) SG(server_context);
-               HashPosition pos;
                int magic_quotes_gpc = PG(magic_quotes_gpc);
-               char *var, **val;
-               uint var_len;
-               ulong idx;
-               int filter_arg = (array_ptr == PG(http_globals)[TRACK_VARS_ENV])?PARSE_ENV:PARSE_SERVER;
 
                /* turn off magic_quotes while importing environment variables */
                PG(magic_quotes_gpc) = 0;
-               for (zend_hash_internal_pointer_reset_ex(&request->env, &pos);
-                       zend_hash_get_current_key_ex(&request->env, &var, &var_len, &idx, 0, &pos) == HASH_KEY_IS_STRING &&
-                       zend_hash_get_current_data_ex(&request->env, (void **) &val, &pos) == SUCCESS;
-                       zend_hash_move_forward_ex(&request->env, &pos)
-               ) {
-                       unsigned int new_val_len;
-
-                       if (sapi_module.input_filter(filter_arg, var, val, strlen(*val), &new_val_len TSRMLS_CC)) {
-                               php_register_variable_safe(var, *val, new_val_len, array_ptr TSRMLS_CC);
-                       }
-               }
+               fcgi_loadenv(request, cgi_php_load_env_var, array_ptr);
                PG(magic_quotes_gpc) = magic_quotes_gpc;
        }
 }
@@ -1100,8 +1096,10 @@ static void init_request_info(TSRMLS_D)
                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);
 
+#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);
+
                if (env_server_software &&
                        env_script_name &&
                        env_path_info &&
@@ -1115,6 +1113,7 @@ static void init_request_info(TSRMLS_D)
                        }
                        env_path_info = _sapi_cgibin_putenv("PATH_INFO", env_path_info TSRMLS_CC);
                }
+#endif
 
                if (CGIG(fix_pathinfo)) {
                        struct stat st;
@@ -1488,7 +1487,7 @@ int main(int argc, char *argv[])
        int fastcgi = fcgi_is_fastcgi();
        char *bindpath = NULL;
        int fcgi_fd = 0;
-       fcgi_request request;
+       fcgi_request *request = NULL;
        int repeats = 1;
        int benchmark = 0;
 #if HAVE_GETTIMEOFDAY
@@ -1689,7 +1688,7 @@ consult the installation file that came with this distribution, or visit \n\
                php_import_environment_variables = cgi_php_import_environment_variables;
 
                /* library is already initialized, now init our request */
-               fcgi_init_request(&request, fcgi_fd);
+               request = fcgi_init_request(fcgi_fd);
 
 #ifndef PHP_WIN32
        /* Pre-fork, if required */
@@ -1810,6 +1809,9 @@ consult the installation file that came with this distribution, or visit \n\
                                        break;
                                case 'h':
                                case '?':
+                                       if (request) {
+                                               fcgi_destroy_request(request);
+                                       }
                                        fcgi_shutdown();
                                        no_headers = 1;
                                        SG(headers_sent) = 1;
@@ -1831,8 +1833,8 @@ consult the installation file that came with this distribution, or visit \n\
                        fcgi_impersonate();
                }
 #endif
-               while (!fastcgi || fcgi_accept_request(&request) >= 0) {
-                       SG(server_context) = (void *) &request;
+               while (!fastcgi || fcgi_accept_request(request) >= 0) {
+                       SG(server_context) = fastcgi ? (void *) request : (void *) 1;
                        init_request_info(TSRMLS_C);
                        CG(interactive) = 0;
 
@@ -2026,7 +2028,7 @@ consult the installation file that came with this distribution, or visit \n\
                         * get path_translated */
                        if (php_request_startup(TSRMLS_C) == FAILURE) {
                                if (fastcgi) {
-                                       fcgi_finish_request(&request, 1);
+                                       fcgi_finish_request(request, 1);
                                }
                                SG(server_context) = NULL;
                                php_module_shutdown(TSRMLS_C);
@@ -2232,7 +2234,7 @@ fastcgi_request_done:
                        /* only fastcgi will get here */
                        requests++;
                        if (max_requests && (requests == max_requests)) {
-                               fcgi_finish_request(&request, 1);
+                               fcgi_finish_request(request, 1);
                                if (bindpath) {
                                        free(bindpath);
                                }
@@ -2244,6 +2246,9 @@ fastcgi_request_done:
                        }
                        /* end of fastcgi loop */
                }
+               if (request) {
+                       fcgi_destroy_request(request);
+               }
                fcgi_shutdown();
 
                if (cgi_sapi_module.php_ini_path_override) {
index 607ca6581e76cbf8ecb6dd57b767324dab9c3433..53d66ea44cedd5825bb260ecbf0686245dbd6790 100644 (file)
@@ -140,6 +140,222 @@ static int is_fastcgi = 0;
 static int in_shutdown = 0;
 static in_addr_t *allowed_clients = NULL;
 
+/* hash table */
+
+#define FCGI_HASH_TABLE_SIZE 64
+#define FCGI_HASH_TABLE_MASK (FCGI_HASH_TABLE_SIZE - 1)
+
+typedef struct _fcgi_hash_bucket {
+       unsigned long             hash_value;
+       unsigned int              var_len;
+       char                     *var;
+       unsigned int              val_len;
+       char                     *val;
+       struct _fcgi_hash_bucket *next;
+       struct _fcgi_hash_bucket *list_next;
+} fcgi_hash_bucket;
+
+typedef struct _fcgi_hash_buckets {
+       unsigned int               idx;
+       struct _fcgi_hash_buckets *next;
+       struct _fcgi_hash_bucket   data[FCGI_HASH_TABLE_SIZE];
+} fcgi_hash_buckets;
+
+typedef struct _fcgi_data_seg {
+       char                  *pos;
+       char                  *end;
+       struct _fcgi_data_seg *next;
+       char                   data[1];
+} fcgi_data_seg;
+
+typedef struct _fcgi_hash {
+       fcgi_hash_bucket  *hash_table[FCGI_HASH_TABLE_SIZE];
+       fcgi_hash_bucket  *list;
+       fcgi_hash_buckets *buckets;
+       fcgi_data_seg     *data;
+} fcgi_hash;
+
+static void fcgi_hash_init(fcgi_hash *h, unsigned int seg_size)
+{
+       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->pos = h->data->data;
+       h->data->end = h->data->pos + seg_size;
+       h->data->next = NULL;
+}
+
+static void fcgi_hash_destroy(fcgi_hash *h)
+{
+       fcgi_hash_buckets *b;
+       fcgi_data_seg *p;
+
+       b = h->buckets;
+       while (b) {
+               fcgi_hash_buckets *q = b;
+               b = b->next;
+               free(q);
+       }               
+       p = h->data;
+       while (p) {
+               fcgi_data_seg *q = p;
+               p = p->next;
+               free(q);
+       }
+}
+
+static void fcgi_hash_clean(fcgi_hash *h)
+{
+       memset(h->hash_table, 0, sizeof(h->hash_table));
+       h->list = NULL;
+       /* delete all bucket blocks except the first one */
+       while (h->buckets->next) {
+               fcgi_hash_buckets *q = h->buckets;
+
+               h->buckets = h->buckets->next;
+               free(q);                
+       }
+       h->buckets->idx = 0;
+       /* delete all data segments except the first one */
+       while (h->data->next) {
+               fcgi_data_seg *q = h->data;
+
+               h->data = h->data->next;
+               free(q);                
+       }
+       h->data->pos = h->data->data;
+}
+
+static inline char* fcgi_hash_strndup(fcgi_hash *h, char *str, unsigned int str_len)
+{
+       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);
+
+               p->pos = p->data;
+               p->end = p->pos + str_len + 1;
+               p->next = h->data;
+               h->data = p; 
+       }
+       memcpy(h->data->pos, str, str_len);
+       str = h->data->pos;
+       h->data->pos[str_len] = 0;
+       h->data->pos += str_len + 1;
+       return str;
+}
+
+static char* fcgi_hash_set(fcgi_hash *h, 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 &&
+                   p->var_len == var_len &&
+                   memcmp(p->var, var, var_len) == 0) {
+
+                       p->val_len = val_len;
+                       p->val = fcgi_hash_strndup(h, val, val_len);
+                       return p->val;
+               }
+               p = p->next;
+       }
+
+       if (UNEXPECTED(h->buckets->idx >= FCGI_HASH_TABLE_SIZE)) {
+               fcgi_hash_buckets *b = (fcgi_hash_buckets*)malloc(sizeof(fcgi_hash_buckets));
+               b->idx = 0;
+               b->next = h->buckets;
+               h->buckets = b;
+       }
+       p = h->buckets->data + h->buckets->idx;
+       h->buckets->idx++;
+       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)
+{
+       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 &&
+                   (*p)->var_len == var_len &&
+                   memcmp((*p)->var, var, var_len) == 0) {
+
+                   (*p)->val = NULL; /* NULL value means deleted */
+                   (*p)->val_len = 0;
+                       *p = (*p)->next;
+                   return;
+               }
+               p = &(*p)->next;
+       }
+}
+
+static char *fcgi_hash_get(fcgi_hash *h, 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];
+
+       while (p != NULL) {
+               if (p->hash_value == hash_value &&
+                   p->var_len == var_len &&
+                   memcmp(p->var, var, var_len) == 0) {
+                   *val_len = p->val_len;
+                   return p->val;
+               }
+               p = p->next;
+       }
+       return NULL;
+}
+
+static void fcgi_hash_apply(fcgi_hash *h, fcgi_apply_func func, void *arg)
+{
+       fcgi_hash_bucket *p     = h->list;
+
+       while (p) {
+               if (EXPECTED(p->val != NULL)) {
+                       func(p->var, p->var_len, p->val, p->val_len, arg);
+               }
+               p = p->list_next;
+       }
+}
+
+struct _fcgi_request {
+       int            listen_socket;
+#ifdef _WIN32
+       int            tcp;
+#endif
+       int            fd;
+       int            id;
+       int            keep;
+       int            closed;
+
+       int            in_len;
+       int            in_pad;
+
+       fcgi_header   *out_hdr;
+       unsigned char *out_pos;
+       unsigned char  out_buf[1024*8];
+       unsigned char  reserved[sizeof(fcgi_end_request_rec)];
+
+       int            has_env;
+       fcgi_hash      env;
+};
+
 #ifdef _WIN32
 
 static DWORD WINAPI fcgi_shutdown_thread(LPVOID arg)
@@ -507,9 +723,9 @@ int fcgi_listen(const char *path, int backlog)
        return listen_socket;
 }
 
-void fcgi_init_request(fcgi_request *req, int listen_socket)
+fcgi_request *fcgi_init_request(int listen_socket)
 {
-       memset(req, 0, sizeof(fcgi_request));
+       fcgi_request *req = (fcgi_request*)calloc(1, sizeof(fcgi_request));
        req->listen_socket = listen_socket;
        req->fd = -1;
        req->id = -1;
@@ -523,6 +739,16 @@ void fcgi_init_request(fcgi_request *req, int listen_socket)
 #ifdef _WIN32
        req->tcp = !GetNamedPipeInfo((HANDLE)_get_osfhandle(req->listen_socket), NULL, NULL, NULL, NULL);
 #endif
+
+       fcgi_hash_init(&req->env, 4096);
+       
+       return req;
+}
+
+void fcgi_destroy_request(fcgi_request *req)
+{
+       fcgi_hash_destroy(&req->env);
+       free(req);
 }
 
 static inline ssize_t safe_write(fcgi_request *req, const void *buf, size_t count)
@@ -603,55 +829,36 @@ static inline int fcgi_make_header(fcgi_header *hdr, fcgi_request_type type, int
 
 static int fcgi_get_params(fcgi_request *req, unsigned char *p, unsigned char *end)
 {
-       char buf[128];
-       char *tmp = buf;
-       int buf_size = sizeof(buf);
-       int name_len, val_len;
-       char *s;
+       unsigned int name_len, val_len;
        int ret = 1;
 
        while (p < end) {
                name_len = *p++;
-               if (name_len >= 128) {
+               if (UNEXPECTED(name_len >= 128)) {
                        name_len = ((name_len & 0x7f) << 24);
                        name_len |= (*p++ << 16);
                        name_len |= (*p++ << 8);
                        name_len |= *p++;
                }
                val_len = *p++;
-               if (val_len >= 128) {
+               if (UNEXPECTED(val_len >= 128)) {
                        val_len = ((val_len & 0x7f) << 24);
                        val_len |= (*p++ << 16);
                        val_len |= (*p++ << 8);
                        val_len |= *p++;
                }
-               if (name_len + val_len < 0 ||
-                   name_len + val_len > end - p) {
+               if (UNEXPECTED(name_len + val_len < 0) ||
+                   UNEXPECTED(name_len + val_len > end - p)) {
                        /* Malformated request */
                        ret = 0;
                        break;
                }
-               if (name_len+1 >= buf_size) {
-                       buf_size = name_len + 64;
-                       tmp = (tmp == buf ? emalloc(buf_size): erealloc(tmp, buf_size));
-               }
-               memcpy(tmp, p, name_len);
-               tmp[name_len] = 0;
-               s = estrndup((char*)p + name_len, val_len);
-               zend_hash_update(&req->env, tmp, name_len+1, &s, sizeof(char*), NULL);
+               fcgi_hash_set(&req->env, (char*)p, name_len, (char*)p + name_len, val_len);
                p += name_len + val_len;
        }
-       if (tmp != buf && tmp != NULL) {
-               efree(tmp);
-       }
        return ret;
 }
 
-static void fcgi_free_var(char **s)
-{
-       efree(*s);
-}
-
 static int fcgi_read_request(fcgi_request *req)
 {
        fcgi_header hdr;
@@ -664,7 +871,6 @@ static int fcgi_read_request(fcgi_request *req)
        req->out_hdr = NULL;
        req->out_pos = req->out_buf;
        req->has_env = 1;
-       zend_hash_init(&req->env, 32, NULL, (void (*)(void *)) fcgi_free_var, 0);
 
        if (safe_read(req, &hdr, sizeof(fcgi_header)) != sizeof(fcgi_header) ||
            hdr.version < FCGI_VERSION_1) {
@@ -691,8 +897,6 @@ static int fcgi_read_request(fcgi_request *req)
        req->id = (hdr.requestIdB1 << 8) + hdr.requestIdB0;
 
        if (hdr.type == FCGI_BEGIN_REQUEST && len == sizeof(fcgi_begin_request)) {
-               char *val;
-
                if (safe_read(req, buf, len+padding) != len+padding) {
                        return 0;
                }
@@ -700,16 +904,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:
-                               val = estrndup("RESPONDER", sizeof("RESPONDER")-1);
-                               zend_hash_update(&req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
+                               fcgi_hash_set(&req->env, "FCGI_ROLE", sizeof("FCGI_ROLE")-1, "RESPONDER", sizeof("RESPONDER")-1);
                                break;
                        case FCGI_AUTHORIZER:
-                               val = estrndup("AUTHORIZER", sizeof("AUTHORIZER")-1);
-                               zend_hash_update(&req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
+                               fcgi_hash_set(&req->env, "FCGI_ROLE", sizeof("FCGI_ROLE")-1, "AUTHORIZER", sizeof("AUTHORIZER")-1);
                                break;
                        case FCGI_FILTER:
-                               val = estrndup("FILTER", sizeof("FILTER")-1);
-                               zend_hash_update(&req->env, "FCGI_ROLE", sizeof("FCGI_ROLE"), &val, sizeof(char*), NULL);
+                               fcgi_hash_set(&req->env, "FCGI_ROLE", sizeof("FCGI_ROLE")-1, "FILTER", sizeof("FILTER")-1);
                                break;
                        default:
                                return 0;
@@ -748,12 +949,9 @@ static int fcgi_read_request(fcgi_request *req)
                }
        } else if (hdr.type == FCGI_GET_VALUES) {
                unsigned char *p = buf + sizeof(fcgi_header);
-               HashPosition pos;
-               char * str_index;
-               uint str_length;
-               ulong num_index;
-               int key_type;
                zval ** value;
+               unsigned int zlen;
+               fcgi_hash_bucket *q;
 
                if (safe_read(req, buf, len+padding) != len+padding) {
                        req->keep = 0;
@@ -765,28 +963,22 @@ static int fcgi_read_request(fcgi_request *req)
                        return 0;
                }
 
-               zend_hash_internal_pointer_reset_ex(&req->env, &pos);
-               while ((key_type = zend_hash_get_current_key_ex(&req->env, &str_index, &str_length, &num_index, 0, &pos)) != HASH_KEY_NON_EXISTANT) {
-                       int zlen;
-                       zend_hash_move_forward_ex(&req->env, &pos);
-                       if (key_type != HASH_KEY_IS_STRING) {
-                               continue;
-                       }
-                       if (zend_hash_find(&fcgi_mgmt_vars, str_index, str_length, (void**) &value) != SUCCESS) {
+               q = req->env.list;
+               while (q != NULL) {
+                       if (zend_hash_find(&fcgi_mgmt_vars, q->var, q->var_len, (void**) &value) != SUCCESS) {
                                continue;
                        }
-                       --str_length;
                        zlen = Z_STRLEN_PP(value);
-                       if ((p + 4 + 4 + str_length + zlen) >= (buf + sizeof(buf))) {
+                       if ((p + 4 + 4 + q->var_len + zlen) >= (buf + sizeof(buf))) {
                                break;
                        }
-                       if (str_length < 0x80) {
-                               *p++ = str_length;
+                       if (q->var_len < 0x80) {
+                               *p++ = q->var_len;
                        } else {
-                               *p++ = ((str_length >> 24) & 0xff) | 0x80;
-                               *p++ = (str_length >> 16) & 0xff;
-                               *p++ = (str_length >> 8) & 0xff;
-                               *p++ = str_length & 0xff;
+                               *p++ = ((q->var_len >> 24) & 0xff) | 0x80;
+                               *p++ = (q->var_len >> 16) & 0xff;
+                               *p++ = (q->var_len >> 8) & 0xff;
+                               *p++ = q->var_len & 0xff;
                        }
                        if (zlen < 0x80) {
                                *p++ = zlen;
@@ -796,8 +988,8 @@ static int fcgi_read_request(fcgi_request *req)
                                *p++ = (zlen >> 8) & 0xff;
                                *p++ = zlen & 0xff;
                        }
-                       memcpy(p, str_index, str_length);
-                       p += str_length;
+                       memcpy(p, q->var, q->var_len);
+                       p += q->var_len;
                        memcpy(p, Z_STRVAL_PP(value), zlen);
                        p += zlen;
                }
@@ -871,7 +1063,7 @@ int fcgi_read(fcgi_request *req, char *str, int len)
 static inline void fcgi_close(fcgi_request *req, int force, int destroy)
 {
        if (destroy && req->has_env) {
-               zend_hash_destroy(&req->env);
+               fcgi_hash_clean(&req->env);
                req->has_env = 0;
        }
 
@@ -1224,33 +1416,30 @@ int fcgi_finish_request(fcgi_request *req, int force_close)
 
 char* fcgi_getenv(fcgi_request *req, const char* var, int var_len)
 {
-       char **val;
+       unsigned int val_len;
 
        if (!req) return NULL;
 
-       if (zend_hash_find(&req->env, (char*)var, var_len+1, (void**)&val) == SUCCESS) {
-               return *val;
-       }
-       return NULL;
+       return fcgi_hash_get(&req->env, (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) {
-                       zend_hash_del(&req->env, var, var_len+1);
+                       fcgi_hash_del(&req->env, var, var_len);
                } else {
-                       char **ret;
-
-                       val = estrdup(val);
-                       if (zend_hash_update(&req->env, var, var_len+1, &val, sizeof(char*), (void**)&ret) == SUCCESS) {
-                               return *ret;
-                       }
+                       return fcgi_hash_set(&req->env, var, var_len+1, val, strlen(val));
                }
        }
        return NULL;
 }
 
+void fcgi_loadenv(fcgi_request *req, fcgi_apply_func func, zval *array)
+{
+       fcgi_hash_apply(&req->env, func, array);
+}
+
 #ifdef _WIN32
 void fcgi_impersonate(void)
 {
@@ -1270,7 +1459,7 @@ void fcgi_set_mgmt_var(const char * name, size_t name_len, const char * value, s
        Z_TYPE_P(zvalue) = IS_STRING;
        Z_STRVAL_P(zvalue) = pestrndup(value, value_len, 1);
        Z_STRLEN_P(zvalue) = value_len;
-       zend_hash_add(&fcgi_mgmt_vars, name, name_len + 1, &zvalue, sizeof(zvalue), NULL);
+       zend_hash_add(&fcgi_mgmt_vars, name, name_len, &zvalue, sizeof(zvalue), NULL);
 }
 
 void fcgi_free_mgmt_var_cb(void * ptr)
index 28836415cd4613e41694c16b4a4090ad8a6a3447..d708888c39623e989f642cd1598453b6a186b8b9 100644 (file)
@@ -91,39 +91,23 @@ typedef struct _fcgi_end_request_rec {
 
 /* FastCGI client API */
 
-typedef struct _fcgi_request {
-       int            listen_socket;
-#ifdef _WIN32
-       int            tcp;
-#endif
-       int            fd;
-       int            id;
-       int            keep;
-       int            closed;
-
-       int            in_len;
-       int            in_pad;
-
-       fcgi_header   *out_hdr;
-       unsigned char *out_pos;
-       unsigned char  out_buf[1024*8];
-       unsigned char  reserved[sizeof(fcgi_end_request_rec)];
+typedef void (*fcgi_apply_func)(char *var, unsigned int var_len, char *val, unsigned int val_len, void *arg);
 
-       int            has_env;
-       HashTable      env;
-} fcgi_request;
+typedef struct _fcgi_request fcgi_request;
 
 int fcgi_init(void);
 void fcgi_shutdown(void);
 int fcgi_is_fastcgi(void);
 int fcgi_in_shutdown(void);
 int fcgi_listen(const char *path, int backlog);
-void fcgi_init_request(fcgi_request *req, int listen_socket);
+fcgi_request* fcgi_init_request(int listen_socket);
+void fcgi_destroy_request(fcgi_request *req);
 int fcgi_accept_request(fcgi_request *req);
 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);
+void  fcgi_loadenv(fcgi_request *req, fcgi_apply_func load_func, zval *array);
 
 int fcgi_read(fcgi_request *req, char *str, int len);