From 73d987a41108aa52f479e4715711e8e5d34fffb8 Mon Sep 17 00:00:00 2001 From: Igor Sysoev Date: Sun, 4 May 2008 09:29:43 +0000 Subject: [PATCH] r1699, r1700, r1701, r1702, r1707 merge: upstream parse_header fix and optimization, fix fastcgi_catch_stderr segfault merged in r1524: *) return NGX_HTTP_UPSTREAM_INVALID_HEADER for invalid status *) return NGX_ERROR instead of NGX_HTTP_INTERNAL_SERVER_ERROR in u->parse_header() *) return NGX_HTTP_UPSTREAM_INVALID_HEADER instead of NGX_HTTP_BAD_GATEWAY to go to a next upstream on invalid_header condition *) now ngx_conf_set_str_array_slot() tests NGX_CONF_UNSET_PTR this fixes fastcgi_catch_stderr segfault *) ngx_http_upstream_hide_headers_hash() *) proxy/fastcgi pass_header/hide_header use ngx_http_upstream_hide_headers_hash() --- src/core/ngx_conf_file.c | 2 +- src/http/modules/ngx_http_fastcgi_module.c | 134 ++++----------------- src/http/modules/ngx_http_proxy_module.c | 124 +++---------------- src/http/ngx_http_upstream.c | 109 ++++++++++++++++- src/http/ngx_http_upstream.h | 3 + 5 files changed, 152 insertions(+), 220 deletions(-) diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c index c5cfded99..90cd30c9b 100644 --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -925,7 +925,7 @@ ngx_conf_set_str_array_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) a = (ngx_array_t **) (p + cmd->offset); - if (*a == NULL) { + if (*a == NGX_CONF_UNSET_PTR) { *a = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t)); if (*a == NULL) { return NGX_CONF_ERROR; diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index df8054466..15909fca6 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -885,7 +885,7 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) if (f == NULL) { f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t)); if (f == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } ngx_http_set_ctx(r, f, ngx_http_fastcgi_module); @@ -993,7 +993,7 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) for (i = 0; i < flcf->catch_stderr->nelts; i++) { if (ngx_strstr(line.data, pattern[i].data)) { - return NGX_HTTP_BAD_GATEWAY; + return NGX_HTTP_UPSTREAM_INVALID_HEADER; } } } @@ -1061,7 +1061,7 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) h = ngx_list_push(&u->headers_in.headers); if (h == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } if (f->split_parts && f->split_parts->nelts) { @@ -1075,7 +1075,7 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) p = ngx_palloc(r->pool, size); if (p == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } buf.pos = p; @@ -1103,7 +1103,7 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) h->lowcase_key = ngx_palloc(r->pool, h->key.len); if (h->lowcase_key == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } } else { @@ -1115,7 +1115,7 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) h->key.len + 1 + h->value.len + 1 + h->key.len); if (h->key.data == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } h->value.data = h->key.data + h->key.len + 1; @@ -1143,7 +1143,7 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) h->lowcase_key, h->key.len); if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -1172,7 +1172,10 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) status = ngx_atoi(status_line->data, 3); if (status == NGX_ERROR) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent invalid status \"%V\"", + status_line); + return NGX_HTTP_UPSTREAM_INVALID_HEADER; } u->headers_in.status_n = status; @@ -1233,7 +1236,7 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) f->split_parts = ngx_array_create(r->pool, 1, sizeof(ngx_http_fastcgi_split_part_t)); if (f->split_parts == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } } @@ -1638,8 +1641,6 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf) * conf->upstream.next_upstream = 0; * conf->upstream.temp_path = NULL; * conf->upstream.hide_headers_hash = { NULL, 0 }; - * conf->upstream.hide_headers = NULL; - * conf->upstream.pass_headers = NULL; * conf->upstream.schema = { 0, NULL }; * conf->upstream.uri = { 0, NULL }; * conf->upstream.location = NULL; @@ -1669,6 +1670,9 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf) conf->upstream.pass_request_headers = NGX_CONF_UNSET; conf->upstream.pass_request_body = NGX_CONF_UNSET; + conf->upstream.hide_headers = NGX_CONF_UNSET_PTR; + conf->upstream.pass_headers = NGX_CONF_UNSET_PTR; + conf->upstream.intercept_errors = NGX_CONF_UNSET; /* "fastcgi_cyclic_temp_file" is disabled */ @@ -1689,11 +1693,8 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) u_char *p; size_t size; uintptr_t *code; - ngx_str_t *header; - ngx_uint_t i, j; - ngx_array_t hide_headers; + ngx_uint_t i; 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; @@ -1855,108 +1856,19 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->index, prev->index, ""); - if (conf->upstream.hide_headers == NULL - && conf->upstream.pass_headers == NULL) - { - conf->upstream.hide_headers = prev->upstream.hide_headers; - conf->upstream.pass_headers = prev->upstream.pass_headers; - conf->upstream.hide_headers_hash = prev->upstream.hide_headers_hash; + hash.max_size = 512; + hash.bucket_size = ngx_align(64, ngx_cacheline_size); + hash.name = "fastcgi_hide_headers_hash"; - if (conf->upstream.hide_headers_hash.buckets) { - goto peers; - } - - } else { - if (conf->upstream.hide_headers == NULL) { - conf->upstream.hide_headers = prev->upstream.hide_headers; - } - - if (conf->upstream.pass_headers == NULL) { - conf->upstream.pass_headers = prev->upstream.pass_headers; - } - } - - if (ngx_array_init(&hide_headers, cf->temp_pool, 4, sizeof(ngx_hash_key_t)) + if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream, + &prev->upstream, + ngx_http_fastcgi_hide_headers, + &hash) != NGX_OK) { return NGX_CONF_ERROR; } - for (header = ngx_http_fastcgi_hide_headers; header->len; header++) { - hk = ngx_array_push(&hide_headers); - if (hk == NULL) { - return NGX_CONF_ERROR; - } - - hk->key = *header; - hk->key_hash = ngx_hash_key_lc(header->data, header->len); - hk->value = (void *) 1; - } - - if (conf->upstream.hide_headers) { - - header = conf->upstream.hide_headers->elts; - - for (i = 0; i < conf->upstream.hide_headers->nelts; i++) { - - hk = hide_headers.elts; - - for (j = 0; j < hide_headers.nelts; j++) { - if (ngx_strcasecmp(header[i].data, hk[j].key.data) == 0) { - goto exist; - } - } - - hk = ngx_array_push(&hide_headers); - if (hk == NULL) { - return NGX_CONF_ERROR; - } - - hk->key = header[i]; - hk->key_hash = ngx_hash_key_lc(header[i].data, header[i].len); - hk->value = (void *) 1; - - exist: - - continue; - } - } - - if (conf->upstream.pass_headers) { - - hk = hide_headers.elts; - header = conf->upstream.pass_headers->elts; - - for (i = 0; i < conf->upstream.pass_headers->nelts; i++) { - - for (j = 0; j < hide_headers.nelts; j++) { - - if (hk[j].key.data == NULL) { - continue; - } - - if (ngx_strcasecmp(header[i].data, hk[j].key.data) == 0) { - hk[j].key.data = NULL; - break; - } - } - } - } - - hash.hash = &conf->upstream.hide_headers_hash; - hash.key = ngx_hash_key_lc; - hash.max_size = 512; - hash.bucket_size = ngx_align(64, ngx_cacheline_size); - hash.name = "fastcgi_hide_headers_hash"; - hash.pool = cf->pool; - hash.temp_pool = NULL; - - if (ngx_hash_init(&hash, hide_headers.elts, hide_headers.nelts) != NGX_OK) { - return NGX_CONF_ERROR; - } - -peers: - if (conf->upstream.upstream == NULL) { conf->upstream.upstream = prev->upstream.upstream; conf->upstream.schema = prev->upstream.schema; diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 9eae90324..bd166a4d5 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -838,7 +838,7 @@ ngx_http_proxy_process_status_line(ngx_http_request_t *r) p = ngx_http_get_module_ctx(r, ngx_http_proxy_module); if (p == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } rc = ngx_http_proxy_parse_status_line(r, p); @@ -873,7 +873,7 @@ ngx_http_proxy_process_status_line(ngx_http_request_t *r) u->headers_in.status_line.data = ngx_palloc(r->pool, u->headers_in.status_line.len); if (u->headers_in.status_line.data == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } ngx_memcpy(u->headers_in.status_line.data, p->status_start, @@ -1117,7 +1117,7 @@ ngx_http_proxy_process_header(ngx_http_request_t *r) h = ngx_list_push(&r->upstream->headers_in.headers); if (h == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } h->hash = r->header_hash; @@ -1128,7 +1128,7 @@ ngx_http_proxy_process_header(ngx_http_request_t *r) h->key.data = ngx_palloc(r->pool, h->key.len + 1 + h->value.len + 1 + h->key.len); if (h->key.data == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } h->value.data = h->key.data + h->key.len + 1; @@ -1150,7 +1150,7 @@ ngx_http_proxy_process_header(ngx_http_request_t *r) h->lowcase_key, h->key.len); if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -1175,7 +1175,7 @@ ngx_http_proxy_process_header(ngx_http_request_t *r) if (r->upstream->headers_in.server == NULL) { h = ngx_list_push(&r->upstream->headers_in.headers); if (h == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash( @@ -1191,7 +1191,7 @@ ngx_http_proxy_process_header(ngx_http_request_t *r) if (r->upstream->headers_in.date == NULL) { h = ngx_list_push(&r->upstream->headers_in.headers); if (h == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e'); @@ -1502,8 +1502,6 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) * conf->upstream.next_upstream = 0; * conf->upstream.temp_path = NULL; * conf->upstream.hide_headers_hash = { NULL, 0 }; - * conf->upstream.hide_headers = NULL; - * conf->upstream.pass_headers = NULL; * conf->upstream.schema = { 0, NULL }; * conf->upstream.uri = { 0, NULL }; * conf->upstream.location = NULL; @@ -1540,6 +1538,9 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) conf->upstream.pass_request_headers = NGX_CONF_UNSET; conf->upstream.pass_request_body = NGX_CONF_UNSET; + conf->upstream.hide_headers = NGX_CONF_UNSET_PTR; + conf->upstream.pass_headers = NGX_CONF_UNSET_PTR; + conf->upstream.intercept_errors = NGX_CONF_UNSET; /* "proxy_cyclic_temp_file" is disabled */ @@ -1564,9 +1565,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) u_char *p; size_t size; uintptr_t *code; - ngx_str_t *header; - ngx_uint_t i, j; - ngx_array_t hide_headers; + ngx_uint_t i; ngx_keyval_t *src, *s, *h; ngx_hash_key_t *hk; ngx_hash_init_t hash; @@ -1775,107 +1774,18 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) conf->headers_hash_bucket_size = ngx_align(conf->headers_hash_bucket_size, ngx_cacheline_size); - if (conf->upstream.hide_headers == NULL - && conf->upstream.pass_headers == NULL) - { - conf->upstream.hide_headers = prev->upstream.hide_headers; - conf->upstream.pass_headers = prev->upstream.pass_headers; - conf->upstream.hide_headers_hash = prev->upstream.hide_headers_hash; + hash.max_size = conf->headers_hash_max_size; + hash.bucket_size = conf->headers_hash_bucket_size; + hash.name = "proxy_headers_hash"; - if (conf->upstream.hide_headers_hash.buckets) { - goto peers; - } - - } else { - if (conf->upstream.hide_headers == NULL) { - conf->upstream.hide_headers = prev->upstream.hide_headers; - } - - if (conf->upstream.pass_headers == NULL) { - conf->upstream.pass_headers = prev->upstream.pass_headers; - } - } - - if (ngx_array_init(&hide_headers, cf->temp_pool, 4, sizeof(ngx_hash_key_t)) + if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream, + &prev->upstream, + ngx_http_proxy_hide_headers, &hash) != NGX_OK) { return NGX_CONF_ERROR; } - for (header = ngx_http_proxy_hide_headers; header->len; header++) { - hk = ngx_array_push(&hide_headers); - if (hk == NULL) { - return NGX_CONF_ERROR; - } - - hk->key = *header; - hk->key_hash = ngx_hash_key_lc(header->data, header->len); - hk->value = (void *) 1; - } - - if (conf->upstream.hide_headers) { - - header = conf->upstream.hide_headers->elts; - - for (i = 0; i < conf->upstream.hide_headers->nelts; i++) { - - hk = hide_headers.elts; - - for (j = 0; j < hide_headers.nelts; j++) { - if (ngx_strcasecmp(header[i].data, hk[j].key.data) == 0) { - goto exist; - } - } - - hk = ngx_array_push(&hide_headers); - if (hk == NULL) { - return NGX_CONF_ERROR; - } - - hk->key = header[i]; - hk->key_hash = ngx_hash_key_lc(header[i].data, header[i].len); - hk->value = (void *) 1; - - exist: - - continue; - } - } - - if (conf->upstream.pass_headers) { - - hk = hide_headers.elts; - header = conf->upstream.pass_headers->elts; - - for (i = 0; i < conf->upstream.pass_headers->nelts; i++) { - for (j = 0; j < hide_headers.nelts; j++) { - - if (hk[j].key.data == NULL) { - continue; - } - - if (ngx_strcasecmp(header[i].data, hk[j].key.data) == 0) { - hk[j].key.data = NULL; - break; - } - } - } - } - - hash.hash = &conf->upstream.hide_headers_hash; - hash.key = ngx_hash_key_lc; - hash.max_size = conf->headers_hash_max_size; - hash.bucket_size = conf->headers_hash_bucket_size; - hash.name = "proxy_headers_hash"; - hash.pool = cf->pool; - hash.temp_pool = NULL; - - if (ngx_hash_init(&hash, hide_headers.elts, hide_headers.nelts) != NGX_OK) { - return NGX_CONF_ERROR; - } - -peers: - if (conf->upstream.upstream == NULL) { conf->upstream.upstream = prev->upstream.upstream; diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index a407a1787..f4daf401d 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -1041,7 +1041,7 @@ ngx_http_upstream_process_header(ngx_event_t *rev) return; } - if (rc == NGX_ERROR || rc == NGX_HTTP_INTERNAL_SERVER_ERROR) { + if (rc == NGX_ERROR) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); return; @@ -3265,6 +3265,113 @@ ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags) } +ngx_int_t +ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf, + ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev, + ngx_str_t *default_hide_headers, ngx_hash_init_t *hash) +{ + ngx_str_t *h; + ngx_uint_t i, j; + ngx_array_t hide_headers; + ngx_hash_key_t *hk; + + if (conf->hide_headers == NGX_CONF_UNSET_PTR + && conf->pass_headers == NGX_CONF_UNSET_PTR) + { + conf->hide_headers_hash = prev->hide_headers_hash; + + if (conf->hide_headers_hash.buckets) { + return NGX_OK; + } + + conf->hide_headers = prev->hide_headers; + conf->pass_headers = prev->pass_headers; + + } else { + if (conf->hide_headers == NGX_CONF_UNSET_PTR) { + conf->hide_headers = prev->hide_headers; + } + + if (conf->pass_headers == NGX_CONF_UNSET_PTR) { + conf->pass_headers = prev->pass_headers; + } + } + + if (ngx_array_init(&hide_headers, cf->temp_pool, 4, sizeof(ngx_hash_key_t)) + != NGX_OK) + { + return NGX_ERROR; + } + + for (h = default_hide_headers; h->len; h++) { + hk = ngx_array_push(&hide_headers); + if (hk == NULL) { + return NGX_ERROR; + } + + hk->key = *h; + hk->key_hash = ngx_hash_key_lc(h->data, h->len); + hk->value = (void *) 1; + } + + if (conf->hide_headers != NGX_CONF_UNSET_PTR) { + + h = conf->hide_headers->elts; + + for (i = 0; i < conf->hide_headers->nelts; i++) { + + hk = hide_headers.elts; + + for (j = 0; j < hide_headers.nelts; j++) { + if (ngx_strcasecmp(h[i].data, hk[j].key.data) == 0) { + goto exist; + } + } + + hk = ngx_array_push(&hide_headers); + if (hk == NULL) { + return NGX_ERROR; + } + + hk->key = h[i]; + hk->key_hash = ngx_hash_key_lc(h[i].data, h[i].len); + hk->value = (void *) 1; + + exist: + + continue; + } + } + + if (conf->pass_headers != NGX_CONF_UNSET_PTR) { + + h = conf->pass_headers->elts; + hk = hide_headers.elts; + + for (i = 0; i < conf->pass_headers->nelts; i++) { + for (j = 0; j < hide_headers.nelts; j++) { + + if (hk[j].key.data == NULL) { + continue; + } + + if (ngx_strcasecmp(h[i].data, hk[j].key.data) == 0) { + hk[j].key.data = NULL; + break; + } + } + } + } + + hash->hash = &conf->hide_headers_hash; + hash->key = ngx_hash_key_lc; + hash->pool = cf->pool; + hash->temp_pool = NULL; + + return ngx_hash_init(hash, hide_headers.elts, hide_headers.nelts); +} + + static void * ngx_http_upstream_create_main_conf(ngx_conf_t *cf) { diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index c1ec48fcc..15987b1b1 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -259,6 +259,9 @@ ngx_int_t ngx_http_upstream_header_variable(ngx_http_request_t *r, void ngx_http_upstream_init(ngx_http_request_t *r); ngx_http_upstream_srv_conf_t *ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags); +ngx_int_t ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf, + ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev, + ngx_str_t *default_hide_headers, ngx_hash_init_t *hash); #define ngx_http_conf_upstream_srv_conf(uscf, module) \