Mercurial > hg > nginx-vendor-current
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; }