diff src/http/modules/ngx_http_fastcgi_module.c @ 576:01f2313e34f1 NGINX_0_8_40

nginx 0.8.40 *) Security: now nginx/Windows ignores default file stream name. Thanks to Jose Antonio Vazquez Gonzalez. *) Feature: the ngx_http_uwsgi_module. Thanks to Roberto De Ioris. *) Feature: a "fastcgi_param" directive with value starting with "HTTP_" overrides a client request header line. *) Bugfix: the "If-Modified-Since", "If-Range", etc. client request header lines were passed to FastCGI-server while caching. *) Bugfix: listen unix domain socket could not be changed during reconfiguration. Thanks to Maxim Dounin.
author Igor Sysoev <http://sysoev.ru>
date Mon, 07 Jun 2010 00:00:00 +0400
parents ff463db0be31
children bc110f60c0de
line wrap: on
line diff
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -23,6 +23,9 @@ typedef struct {
     ngx_array_t                   *fastcgi_lengths;
     ngx_array_t                   *fastcgi_values;
 
+    ngx_hash_t                     headers_hash;
+    ngx_uint_t                     header_params;
+
 #if (NGX_HTTP_CACHE)
     ngx_http_complex_value_t       cache_key;
 #endif
@@ -533,6 +536,17 @@ static ngx_str_t  ngx_http_fastcgi_hide_
     ngx_null_string
 };
 
+
+static ngx_keyval_t  ngx_http_fastcgi_cache_headers[] = {
+    { ngx_string("HTTP_IF_MODIFIED_SINCE"), ngx_string("") },
+    { ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") },
+    { ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("") },
+    { ngx_string("HTTP_IF_MATCH"), ngx_string("") },
+    { ngx_string("HTTP_RANGE"), ngx_string("") },
+    { ngx_string("HTTP_IF_RANGE"), ngx_string("") },
+    { ngx_null_string, ngx_null_string }
+};
+
 #endif
 
 
@@ -692,13 +706,14 @@ static ngx_int_t
 ngx_http_fastcgi_create_request(ngx_http_request_t *r)
 {
     off_t                         file_pos;
-    u_char                        ch, *pos;
-    size_t                        size, len, key_len, val_len, padding;
-    ngx_uint_t                    i, n, next;
+    u_char                        ch, *pos, *lowcase_key;
+    size_t                        size, len, key_len, val_len, padding,
+                                  allocated;
+    ngx_uint_t                    i, n, next, hash, header_params;
     ngx_buf_t                    *b;
     ngx_chain_t                  *cl, *body;
     ngx_list_part_t              *part;
-    ngx_table_elt_t              *header;
+    ngx_table_elt_t              *header, **ignored;
     ngx_http_script_code_pt       code;
     ngx_http_script_engine_t      e, le;
     ngx_http_fastcgi_header_t    *h;
@@ -706,6 +721,8 @@ ngx_http_fastcgi_create_request(ngx_http
     ngx_http_script_len_code_pt   lcode;
 
     len = 0;
+    header_params = 0;
+    ignored = NULL;
 
     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
 
@@ -734,6 +751,16 @@ ngx_http_fastcgi_create_request(ngx_http
 
     if (flcf->upstream.pass_request_headers) {
 
+        allocated = 0;
+        lowcase_key = NULL;
+
+        if (flcf->header_params) {
+            ignored = ngx_palloc(r->pool, flcf->header_params * sizeof(void *));
+            if (ignored == NULL) {
+                return NGX_ERROR;
+            }
+        }
+
         part = &r->headers_in.headers.part;
         header = part->elts;
 
@@ -749,9 +776,44 @@ ngx_http_fastcgi_create_request(ngx_http
                 i = 0;
             }
 
-            len += ((sizeof("HTTP_") - 1 + header[i].key.len > 127) ? 4 : 1)
-                + ((header[i].value.len > 127) ? 4 : 1)
-                + sizeof("HTTP_") - 1 + header[i].key.len + header[i].value.len;
+            if (flcf->header_params) {
+                if (allocated < header[i].key.len) {
+                    allocated = header[i].key.len + 16;
+                    lowcase_key = ngx_pnalloc(r->pool, allocated);
+                    if (lowcase_key == NULL) {
+                        return NGX_ERROR;
+                    }
+                }
+
+                hash = 0;
+
+                for (n = 0; n < header[i].key.len; n++) {
+                    ch = header[i].key.data[n];
+
+                    if (ch >= 'A' && ch <= 'Z') {
+                        ch |= 0x20;
+
+                    } else if (ch == '-') {
+                        ch = '_';
+                    }
+
+                    hash = ngx_hash(hash, ch);
+                    lowcase_key[n] = ch;
+                }
+
+                if (ngx_hash_find(&flcf->headers_hash, hash, lowcase_key, n)) {
+                    ignored[header_params++] = &header[i];
+                    continue;
+                }
+
+                n += sizeof("HTTP_") - 1;
+
+            } else {
+                n = sizeof("HTTP_") - 1 + header[i].key.len;
+            }
+
+            len += ((n > 127) ? 4 : 1) + ((header[i].value.len > 127) ? 4 : 1)
+                + n + header[i].value.len;
         }
     }
 
@@ -871,26 +933,32 @@ ngx_http_fastcgi_create_request(ngx_http
                 i = 0;
             }
 
-            len = sizeof("HTTP_") - 1 + header[i].key.len;
-            if (len > 127) {
-                *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
-                *b->last++ = (u_char) ((len >> 16) & 0xff);
-                *b->last++ = (u_char) ((len >> 8) & 0xff);
-                *b->last++ = (u_char) (len & 0xff);
+            for (n = 0; n < header_params; n++) {
+                if (&header[i] == ignored[n]) {
+                    goto next;
+                }
+            }
+
+            key_len = sizeof("HTTP_") - 1 + header[i].key.len;
+            if (key_len > 127) {
+                *b->last++ = (u_char) (((key_len >> 24) & 0x7f) | 0x80);
+                *b->last++ = (u_char) ((key_len >> 16) & 0xff);
+                *b->last++ = (u_char) ((key_len >> 8) & 0xff);
+                *b->last++ = (u_char) (key_len & 0xff);
 
             } else {
-                *b->last++ = (u_char) len;
+                *b->last++ = (u_char) key_len;
             }
 
-            len = header[i].value.len;
-            if (len > 127) {
-                *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
-                *b->last++ = (u_char) ((len >> 16) & 0xff);
-                *b->last++ = (u_char) ((len >> 8) & 0xff);
-                *b->last++ = (u_char) (len & 0xff);
+            val_len = header[i].value.len;
+            if (val_len > 127) {
+                *b->last++ = (u_char) (((val_len >> 24) & 0x7f) | 0x80);
+                *b->last++ = (u_char) ((val_len >> 16) & 0xff);
+                *b->last++ = (u_char) ((val_len >> 8) & 0xff);
+                *b->last++ = (u_char) (val_len & 0xff);
 
             } else {
-                *b->last++ = (u_char) len;
+                *b->last++ = (u_char) val_len;
             }
 
             b->last = ngx_cpymem(b->last, "HTTP_", sizeof("HTTP_") - 1);
@@ -908,8 +976,15 @@ ngx_http_fastcgi_create_request(ngx_http
                 *b->last++ = ch;
             }
 
-            b->last = ngx_copy(b->last, header[i].value.data,
-                               header[i].value.len);
+            b->last = ngx_copy(b->last, header[i].value.data, val_len);
+
+            ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "fastcgi param: \"%*s: %*s\"",
+                           key_len, b->last - (key_len + val_len),
+                           val_len, b->last - val_len);
+        next:
+
+            continue;
         }
     }
 
@@ -1957,9 +2032,11 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
     u_char                       *p;
     size_t                        size;
     uintptr_t                    *code;
-    ngx_str_t                    *h;
+    ngx_str_t                    *hide;
     ngx_uint_t                    i;
+    ngx_array_t                   headers_names;
     ngx_keyval_t                 *src;
+    ngx_hash_key_t               *hk;
     ngx_hash_init_t               hash;
     ngx_http_script_compile_t     sc;
     ngx_http_script_copy_code_t  *copy;
@@ -2183,16 +2260,16 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
 
 #if (NGX_HTTP_CACHE)
 
-    h = conf->upstream.cache ? ngx_http_fastcgi_hide_cache_headers:
-                               ngx_http_fastcgi_hide_headers;
+    hide = conf->upstream.cache ? ngx_http_fastcgi_hide_cache_headers:
+                                  ngx_http_fastcgi_hide_headers;
 #else
 
-    h = ngx_http_fastcgi_hide_headers;
+    hide = ngx_http_fastcgi_hide_headers;
 
 #endif
 
     if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
-                                            &prev->upstream, h, &hash)
+                                            &prev->upstream, hide, &hash)
         != NGX_OK)
     {
         return NGX_CONF_ERROR;
@@ -2219,10 +2296,32 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
         conf->params_len = prev->params_len;
         conf->params = prev->params;
         conf->params_source = prev->params_source;
+        conf->headers_hash = prev->headers_hash;
+
+#if (NGX_HTTP_CACHE)
+
+        if (conf->params_source == NULL) {
+
+            if ((conf->upstream.cache == NULL)
+                == (prev->upstream.cache == NULL))
+            {
+                return NGX_CONF_OK;
+            }
+
+            /* 6 is a number of ngx_http_fastcgi_cache_headers entries */
+            conf->params_source = ngx_array_create(cf->pool, 6,
+                                                   sizeof(ngx_keyval_t));
+            if (conf->params_source == NULL) {
+                return NGX_CONF_ERROR;
+            }
+        }
+#else
 
         if (conf->params_source == NULL) {
             return NGX_CONF_OK;
         }
+
+#endif
     }
 
     conf->params_len = ngx_array_create(cf->pool, 64, 1);
@@ -2235,89 +2334,100 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
         return NGX_CONF_ERROR;
     }
 
+    if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
+        != NGX_OK)
+    {
+        return NGX_CONF_ERROR;
+    }
+
     src = conf->params_source->elts;
-    for (i = 0; i < conf->params_source->nelts; i++) {
-
-        if (ngx_http_script_variables_count(&src[i].value) == 0) {
-            copy = ngx_array_push_n(conf->params_len,
-                                    sizeof(ngx_http_script_copy_code_t));
-            if (copy == NULL) {
+
+#if (NGX_HTTP_CACHE)
+
+    if (conf->upstream.cache) {
+        ngx_keyval_t  *h, *s;
+
+        for (h = ngx_http_fastcgi_cache_headers; h->key.len; h++) {
+
+            for (i = 0; i < conf->params_source->nelts; i++) {
+                if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
+                    goto next;
+                }
+            }
+
+            s = ngx_array_push(conf->params_source);
+            if (s == NULL) {
                 return NGX_CONF_ERROR;
             }
 
-            copy->code = (ngx_http_script_code_pt)
-                                                  ngx_http_script_copy_len_code;
-            copy->len = src[i].key.len;
-
-
-            copy = ngx_array_push_n(conf->params_len,
-                                    sizeof(ngx_http_script_copy_code_t));
-            if (copy == NULL) {
-                return NGX_CONF_ERROR;
-            }
-
-            copy->code = (ngx_http_script_code_pt)
-                                                 ngx_http_script_copy_len_code;
-            copy->len = src[i].value.len;
-
-
-            size = (sizeof(ngx_http_script_copy_code_t)
-                       + src[i].key.len + src[i].value.len
-                       + sizeof(uintptr_t) - 1)
-                    & ~(sizeof(uintptr_t) - 1);
-
-            copy = ngx_array_push_n(conf->params, size);
-            if (copy == NULL) {
+            *s = *h;
+
+            src = conf->params_source->elts;
+
+        next:
+
+            h++;
+        }
+    }
+
+#endif
+
+    for (i = 0; i < conf->params_source->nelts; i++) {
+
+        if (src[i].key.len > sizeof("HTTP_") - 1
+            && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0)
+        {
+            hk = ngx_array_push(&headers_names);
+            if (hk == NULL) {
                 return NGX_CONF_ERROR;
             }
 
-            copy->code = ngx_http_script_copy_code;
-            copy->len = src[i].key.len + src[i].value.len;
-
-            p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
-
-            p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
-            ngx_memcpy(p, src[i].value.data, src[i].value.len);
-
-        } else {
-            copy = ngx_array_push_n(conf->params_len,
-                                    sizeof(ngx_http_script_copy_code_t));
-            if (copy == NULL) {
-                return NGX_CONF_ERROR;
+            hk->key.len = src[i].key.len - 5;
+            hk->key.data = src[i].key.data + 5;
+            hk->key_hash = ngx_hash_key_lc(hk->key.data, hk->key.len);
+            hk->value = (void *) 1;
+
+            if (src[i].value.len == 0) {
+                continue;
             }
-
-            copy->code = (ngx_http_script_code_pt)
-                                                 ngx_http_script_copy_len_code;
-            copy->len = src[i].key.len;
-
-
-            size = (sizeof(ngx_http_script_copy_code_t)
-                    + src[i].key.len + sizeof(uintptr_t) - 1)
-                    & ~(sizeof(uintptr_t) - 1);
-
-            copy = ngx_array_push_n(conf->params, size);
-            if (copy == NULL) {
-                return NGX_CONF_ERROR;
-            }
-
-            copy->code = ngx_http_script_copy_code;
-            copy->len = src[i].key.len;
-
-            p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
-            ngx_memcpy(p, src[i].key.data, src[i].key.len);
-
-
-            ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
-
-            sc.cf = cf;
-            sc.source = &src[i].value;
-            sc.flushes = &conf->flushes;
-            sc.lengths = &conf->params_len;
-            sc.values = &conf->params;
-
-            if (ngx_http_script_compile(&sc) != NGX_OK) {
-                return NGX_CONF_ERROR;
-            }
+        }
+
+        copy = ngx_array_push_n(conf->params_len,
+                                sizeof(ngx_http_script_copy_code_t));
+        if (copy == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
+        copy->len = src[i].key.len;
+
+
+        size = (sizeof(ngx_http_script_copy_code_t)
+                + src[i].key.len + sizeof(uintptr_t) - 1)
+                & ~(sizeof(uintptr_t) - 1);
+
+        copy = ngx_array_push_n(conf->params, size);
+        if (copy == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        copy->code = ngx_http_script_copy_code;
+        copy->len = src[i].key.len;
+
+        p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
+        ngx_memcpy(p, src[i].key.data, src[i].key.len);
+
+
+        ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+
+        sc.cf = cf;
+        sc.source = &src[i].value;
+        sc.flushes = &conf->flushes;
+        sc.lengths = &conf->params_len;
+        sc.values = &conf->params;
+
+        if (ngx_http_script_compile(&sc) != NGX_OK) {
+            return NGX_CONF_ERROR;
         }
 
         code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t));
@@ -2343,6 +2453,22 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
 
     *code = (uintptr_t) NULL;
 
+
+    conf->header_params = headers_names.nelts;
+
+    hash.hash = &conf->headers_hash;
+    hash.key = ngx_hash_key_lc;
+    hash.max_size = 512;
+    hash.bucket_size = 64;
+    hash.name = "fastcgi_params_hash";
+    hash.pool = cf->pool;
+    hash.temp_pool = NULL;
+
+    if (ngx_hash_init(&hash, headers_names.elts, headers_names.nelts) != NGX_OK)
+    {
+        return NGX_CONF_ERROR;
+    }
+
     return NGX_CONF_OK;
 }