diff options
author | nginx <nginx@nginx.org> | 2013-03-05 14:54:11 +0000 |
---|---|---|
committer | Jon Kolb <jon@b0g.us> | 2013-03-05 14:54:11 +0000 |
commit | 72050c25110c60a640ed602b5a99dc3513adf8c2 (patch) | |
tree | 03cd2bf0cc618bf496095e1bcd8713592b4b4344 | |
parent | a36b88c56061d08f8fbe96a51489bf3381792aca (diff) | |
download | nginx-72050c25110c60a640ed602b5a99dc3513adf8c2.tar.gz |
Changes with nginx 1.3.14 05 Mar 2013v1.3.14
*) Feature: $connections_active, $connections_reading, and
$connections_writing variables in the ngx_http_stub_status_module.
*) Feature: support of WebSocket connections in the
ngx_http_uwsgi_module and ngx_http_scgi_module.
*) Bugfix: in virtual servers handling with SNI.
*) Bugfix: new sessions were not always stored if the "ssl_session_cache
shared" directive was used and there was no free space in shared
memory.
Thanks to Piotr Sikora.
*) Bugfix: multiple X-Forwarded-For headers were handled incorrectly.
Thanks to Neal Poole for sponsoring this work.
*) Bugfix: in the ngx_http_mp4_module.
Thanks to Gernot Vormayr.
-rw-r--r-- | CHANGES | 22 | ||||
-rw-r--r-- | CHANGES.ru | 23 | ||||
-rw-r--r-- | src/core/nginx.h | 4 | ||||
-rw-r--r-- | src/event/ngx_event_openssl.c | 24 | ||||
-rw-r--r-- | src/http/modules/ngx_http_geo_module.c | 11 | ||||
-rw-r--r-- | src/http/modules/ngx_http_geoip_module.c | 22 | ||||
-rw-r--r-- | src/http/modules/ngx_http_mp4_module.c | 7 | ||||
-rw-r--r-- | src/http/modules/ngx_http_proxy_module.c | 30 | ||||
-rw-r--r-- | src/http/modules/ngx_http_realip_module.c | 25 | ||||
-rw-r--r-- | src/http/modules/ngx_http_scgi_module.c | 10 | ||||
-rw-r--r-- | src/http/modules/ngx_http_ssl_module.c | 1 | ||||
-rw-r--r-- | src/http/modules/ngx_http_stub_status_module.c | 81 | ||||
-rw-r--r-- | src/http/modules/ngx_http_uwsgi_module.c | 10 | ||||
-rw-r--r-- | src/http/modules/perl/nginx.pm | 2 | ||||
-rw-r--r-- | src/http/ngx_http.h | 2 | ||||
-rw-r--r-- | src/http/ngx_http_core_module.c | 68 | ||||
-rw-r--r-- | src/http/ngx_http_core_module.h | 31 | ||||
-rw-r--r-- | src/http/ngx_http_file_cache.c | 2 | ||||
-rw-r--r-- | src/http/ngx_http_request.c | 788 | ||||
-rw-r--r-- | src/http/ngx_http_request.h | 39 | ||||
-rw-r--r-- | src/http/ngx_http_variables.c | 39 |
21 files changed, 813 insertions, 428 deletions
@@ -1,4 +1,26 @@ +Changes with nginx 1.3.14 05 Mar 2013 + + *) Feature: $connections_active, $connections_reading, and + $connections_writing variables in the ngx_http_stub_status_module. + + *) Feature: support of WebSocket connections in the + ngx_http_uwsgi_module and ngx_http_scgi_module. + + *) Bugfix: in virtual servers handling with SNI. + + *) Bugfix: new sessions were not always stored if the "ssl_session_cache + shared" directive was used and there was no free space in shared + memory. + Thanks to Piotr Sikora. + + *) Bugfix: multiple X-Forwarded-For headers were handled incorrectly. + Thanks to Neal Poole for sponsoring this work. + + *) Bugfix: in the ngx_http_mp4_module. + Thanks to Gernot Vormayr. + + Changes with nginx 1.3.13 19 Feb 2013 *) Change: a compiler with name "cc" is now used by default. diff --git a/CHANGES.ru b/CHANGES.ru index 1d1a3a025..bdf457834 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,27 @@ +Изменения в nginx 1.3.14 05.03.2013 + + *) Добавление: переменные $connections_active, $connections_reading и + $connections_writing в модуле ngx_http_stub_status_module. + + *) Добавление: поддержка WebSocket-соединений в модулях + ngx_http_uwsgi_module и ngx_http_scgi_module. + + *) Исправление: в обработке виртуальных серверов при использовании SNI. + + *) Исправление: при использовании директивы "ssl_session_cache shared" + новые сессии могли не сохраняться, если заканчивалось место в + разделяемой памяти. + Спасибо Piotr Sikora. + + *) Исправление: несколько заголовков X-Forwarded-For обрабатывались + неправильно. + Спасибо Neal Poole за спонсирование разработки. + + *) Исправление: в модуле ngx_http_mp4_module. + Спасибо Gernot Vormayr. + + Изменения в nginx 1.3.13 19.02.2013 *) Изменение: теперь для сборки по умолчанию используется компилятор с diff --git a/src/core/nginx.h b/src/core/nginx.h index f522433e2..f0f3808f1 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1003013 -#define NGINX_VERSION "1.3.13" +#define nginx_version 1003014 +#define NGINX_VERSION "1.3.14" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index b8f1cae91..62ce12c14 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -1842,8 +1842,18 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess) } sess_id = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_sess_id_t)); + if (sess_id == NULL) { - goto failed; + + /* drop the oldest non-expired session and try once more */ + + ngx_ssl_expire_sessions(cache, shpool, 0); + + sess_id = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_sess_id_t)); + + if (sess_id == NULL) { + goto failed; + } } #if (NGX_PTR_SIZE == 8) @@ -1853,8 +1863,18 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess) #else id = ngx_slab_alloc_locked(shpool, sess->session_id_length); + if (id == NULL) { - goto failed; + + /* drop the oldest non-expired session and try once more */ + + ngx_ssl_expire_sessions(cache, shpool, 0); + + id = ngx_slab_alloc_locked(shpool, sess->session_id_length); + + if (id == NULL) { + goto failed; + } } #endif diff --git a/src/http/modules/ngx_http_geo_module.c b/src/http/modules/ngx_http_geo_module.c index a927ab798..725baa211 100644 --- a/src/http/modules/ngx_http_geo_module.c +++ b/src/http/modules/ngx_http_geo_module.c @@ -314,18 +314,17 @@ static ngx_int_t ngx_http_geo_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx, ngx_addr_t *addr) { - ngx_table_elt_t *xfwd; + ngx_array_t *xfwd; if (ngx_http_geo_real_addr(r, ctx, addr) != NGX_OK) { return NGX_ERROR; } - xfwd = r->headers_in.x_forwarded_for; + xfwd = &r->headers_in.x_forwarded_for; - if (xfwd != NULL && ctx->proxies != NULL) { - (void) ngx_http_get_forwarded_addr(r, addr, xfwd->value.data, - xfwd->value.len, ctx->proxies, - ctx->proxy_recursive); + if (xfwd->nelts > 0 && ctx->proxies != NULL) { + (void) ngx_http_get_forwarded_addr(r, addr, xfwd, NULL, + ctx->proxies, ctx->proxy_recursive); } return NGX_OK; diff --git a/src/http/modules/ngx_http_geoip_module.c b/src/http/modules/ngx_http_geoip_module.c index 364106519..576fc5f3c 100644 --- a/src/http/modules/ngx_http_geoip_module.c +++ b/src/http/modules/ngx_http_geoip_module.c @@ -240,19 +240,18 @@ static u_long ngx_http_geoip_addr(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf) { ngx_addr_t addr; - ngx_table_elt_t *xfwd; + ngx_array_t *xfwd; struct sockaddr_in *sin; addr.sockaddr = r->connection->sockaddr; addr.socklen = r->connection->socklen; /* addr.name = r->connection->addr_text; */ - xfwd = r->headers_in.x_forwarded_for; + xfwd = &r->headers_in.x_forwarded_for; - if (xfwd != NULL && gcf->proxies != NULL) { - (void) ngx_http_get_forwarded_addr(r, &addr, xfwd->value.data, - xfwd->value.len, gcf->proxies, - gcf->proxy_recursive); + if (xfwd->nelts > 0 && gcf->proxies != NULL) { + (void) ngx_http_get_forwarded_addr(r, &addr, xfwd, NULL, + gcf->proxies, gcf->proxy_recursive); } #if (NGX_HAVE_INET6) @@ -293,7 +292,7 @@ static geoipv6_t ngx_http_geoip_addr_v6(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf) { ngx_addr_t addr; - ngx_table_elt_t *xfwd; + ngx_array_t *xfwd; in_addr_t addr4; struct in6_addr addr6; struct sockaddr_in *sin; @@ -303,12 +302,11 @@ ngx_http_geoip_addr_v6(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf) addr.socklen = r->connection->socklen; /* addr.name = r->connection->addr_text; */ - xfwd = r->headers_in.x_forwarded_for; + xfwd = &r->headers_in.x_forwarded_for; - if (xfwd != NULL && gcf->proxies != NULL) { - (void) ngx_http_get_forwarded_addr(r, &addr, xfwd->value.data, - xfwd->value.len, gcf->proxies, - gcf->proxy_recursive); + if (xfwd->nelts > 0 && gcf->proxies != NULL) { + (void) ngx_http_get_forwarded_addr(r, &addr, xfwd, NULL, + gcf->proxies, gcf->proxy_recursive); } switch (addr.sockaddr->sa_family) { diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c index b864858ea..20ef51af2 100644 --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -754,6 +754,13 @@ ngx_http_mp4_process(ngx_http_mp4_file_t *mp4) *prev = &mp4->mdat_atom; + if (start_offset > mp4->mdat_data.buf->file_last) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "start time is out mp4 mdat atom in \"%s\"", + mp4->file.name.data); + return NGX_ERROR; + } + adjustment = mp4->ftyp_size + mp4->moov_size + ngx_http_mp4_update_mdat_atom(mp4, start_offset) - start_offset; diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index a623adc34..eadc8c480 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -2014,32 +2014,44 @@ static ngx_int_t ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - u_char *p; + size_t len; + u_char *p; + ngx_uint_t i, n; + ngx_table_elt_t **h; v->valid = 1; v->no_cacheable = 0; v->not_found = 0; - if (r->headers_in.x_forwarded_for == NULL) { + n = r->headers_in.x_forwarded_for.nelts; + h = r->headers_in.x_forwarded_for.elts; + + len = 0; + + for (i = 0; i < n; i++) { + len += h[i]->value.len + sizeof(", ") - 1; + } + + if (len == 0) { v->len = r->connection->addr_text.len; v->data = r->connection->addr_text.data; return NGX_OK; } - v->len = r->headers_in.x_forwarded_for->value.len - + sizeof(", ") - 1 + r->connection->addr_text.len; + len += r->connection->addr_text.len; - p = ngx_pnalloc(r->pool, v->len); + p = ngx_pnalloc(r->pool, len); if (p == NULL) { return NGX_ERROR; } + v->len = len; v->data = p; - p = ngx_copy(p, r->headers_in.x_forwarded_for->value.data, - r->headers_in.x_forwarded_for->value.len); - - *p++ = ','; *p++ = ' '; + for (i = 0; i < n; i++) { + p = ngx_copy(p, h[i]->value.data, h[i]->value.len); + *p++ = ','; *p++ = ' '; + } ngx_memcpy(p, r->connection->addr_text.data, r->connection->addr_text.len); diff --git a/src/http/modules/ngx_http_realip_module.c b/src/http/modules/ngx_http_realip_module.c index 4531ea51c..ed9c5f9e8 100644 --- a/src/http/modules/ngx_http_realip_module.c +++ b/src/http/modules/ngx_http_realip_module.c @@ -107,10 +107,12 @@ ngx_module_t ngx_http_realip_module = { static ngx_int_t ngx_http_realip_handler(ngx_http_request_t *r) { - u_char *ip, *p; + u_char *p; size_t len; + ngx_str_t *value; ngx_uint_t i, hash; ngx_addr_t addr; + ngx_array_t *xfwd; ngx_list_part_t *part; ngx_table_elt_t *header; ngx_connection_t *c; @@ -137,19 +139,20 @@ ngx_http_realip_handler(ngx_http_request_t *r) return NGX_DECLINED; } - len = r->headers_in.x_real_ip->value.len; - ip = r->headers_in.x_real_ip->value.data; + value = &r->headers_in.x_real_ip->value; + xfwd = NULL; break; case NGX_HTTP_REALIP_XFWD: - if (r->headers_in.x_forwarded_for == NULL) { + xfwd = &r->headers_in.x_forwarded_for; + + if (xfwd->elts == NULL) { return NGX_DECLINED; } - len = r->headers_in.x_forwarded_for->value.len; - ip = r->headers_in.x_forwarded_for->value.data; + value = NULL; break; @@ -178,8 +181,8 @@ ngx_http_realip_handler(ngx_http_request_t *r) && len == header[i].key.len && ngx_strncmp(p, header[i].lowcase_key, len) == 0) { - len = header[i].value.len; - ip = header[i].value.data; + value = &header[i].value; + xfwd = NULL; goto found; } @@ -192,15 +195,13 @@ found: c = r->connection; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "realip: \"%s\"", ip); - addr.sockaddr = c->sockaddr; addr.socklen = c->socklen; /* addr.name = c->addr_text; */ - if (ngx_http_get_forwarded_addr(r, &addr, ip, len, rlcf->from, + if (ngx_http_get_forwarded_addr(r, &addr, xfwd, value, rlcf->from, rlcf->recursive) - == NGX_OK) + != NGX_DECLINED) { return ngx_http_realip_set_addr(r, &addr); } diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c index c87b44b53..49cc96d24 100644 --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -984,7 +984,7 @@ ngx_http_scgi_process_header(ngx_http_request_t *r) u = r->upstream; if (u->headers_in.status_n) { - return NGX_OK; + goto done; } if (u->headers_in.status) { @@ -1015,6 +1015,14 @@ ngx_http_scgi_process_header(ngx_http_request_t *r) u->state->status = u->headers_in.status_n; } + done: + + if (u->headers_in.status_n == NGX_HTTP_SWITCHING_PROTOCOLS + && r->headers_in.upgrade) + { + u->upgrade = 1; + } + return NGX_OK; } diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index 62882838d..2fc4ad47c 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -661,7 +661,6 @@ ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) for (j = sizeof("shared:") - 1; j < value[i].len; j++) { if (value[i].data[j] == ':') { - value[i].data[j] = '\0'; break; } diff --git a/src/http/modules/ngx_http_stub_status_module.c b/src/http/modules/ngx_http_stub_status_module.c index 96abe928a..e2ac94928 100644 --- a/src/http/modules/ngx_http_stub_status_module.c +++ b/src/http/modules/ngx_http_stub_status_module.c @@ -10,6 +10,10 @@ #include <ngx_http.h> +static ngx_int_t ngx_http_stub_status_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_stub_status_add_variables(ngx_conf_t *cf); + static char *ngx_http_set_status(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -28,7 +32,7 @@ static ngx_command_t ngx_http_status_commands[] = { static ngx_http_module_t ngx_http_stub_status_module_ctx = { - NULL, /* preconfiguration */ + ngx_http_stub_status_add_variables, /* preconfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ @@ -58,6 +62,21 @@ ngx_module_t ngx_http_stub_status_module = { }; +static ngx_http_variable_t ngx_http_stub_status_vars[] = { + + { ngx_string("connections_active"), NULL, ngx_http_stub_status_variable, + 0, NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("connections_reading"), NULL, ngx_http_stub_status_variable, + 1, NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("connections_writing"), NULL, ngx_http_stub_status_variable, + 2, NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_null_string, NULL, NULL, 0, 0, 0 } +}; + + static ngx_int_t ngx_http_status_handler(ngx_http_request_t *r) { size_t size; @@ -133,6 +152,66 @@ static ngx_int_t ngx_http_status_handler(ngx_http_request_t *r) } +static ngx_int_t +ngx_http_stub_status_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + u_char *p; + ngx_atomic_int_t value; + + p = ngx_pnalloc(r->pool, NGX_ATOMIC_T_LEN); + if (p == NULL) { + return NGX_ERROR; + } + + switch (data) { + case 0: + value = *ngx_stat_active; + break; + + case 1: + value = *ngx_stat_reading; + break; + + case 2: + value = *ngx_stat_writing; + break; + + /* suppress warning */ + default: + value = 0; + break; + } + + v->len = ngx_sprintf(p, "%uA", value) - p; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = p; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_stub_status_add_variables(ngx_conf_t *cf) +{ + ngx_http_variable_t *var, *v; + + for (v = ngx_http_stub_status_vars; v->name.len; v++) { + var = ngx_http_add_variable(cf, &v->name, v->flags); + if (var == NULL) { + return NGX_ERROR; + } + + var->get_handler = v->get_handler; + var->data = v->data; + } + + return NGX_OK; +} + + static char *ngx_http_set_status(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_core_loc_conf_t *clcf; diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c index c683df0be..623ee4957 100644 --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -1018,7 +1018,7 @@ ngx_http_uwsgi_process_header(ngx_http_request_t *r) u = r->upstream; if (u->headers_in.status_n) { - return NGX_OK; + goto done; } if (u->headers_in.status) { @@ -1049,6 +1049,14 @@ ngx_http_uwsgi_process_header(ngx_http_request_t *r) u->state->status = u->headers_in.status_n; } + done: + + if (u->headers_in.status_n == NGX_HTTP_SWITCHING_PROTOCOLS + && r->headers_in.upgrade) + { + u->upgrade = 1; + } + return NGX_OK; } diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm index 353cadb9d..4adb2de9f 100644 --- a/src/http/modules/perl/nginx.pm +++ b/src/http/modules/perl/nginx.pm @@ -50,7 +50,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '1.3.13'; +our $VERSION = '1.3.14'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h index f974081ea..bf70c16a8 100644 --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -27,11 +27,11 @@ typedef u_char *(*ngx_http_log_handler_pt)(ngx_http_request_t *r, #include <ngx_http_variables.h> +#include <ngx_http_config.h> #include <ngx_http_request.h> #include <ngx_http_script.h> #include <ngx_http_upstream.h> #include <ngx_http_upstream_round_robin.h> -#include <ngx_http_config.h> #include <ngx_http_busy_lock.h> #include <ngx_http_core_module.h> diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 27f082ee7..c4914997b 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -76,6 +76,9 @@ static ngx_uint_t ngx_http_gzip_quantity(u_char *p, u_char *last); static char *ngx_http_gzip_disable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); #endif +static ngx_int_t ngx_http_get_forwarded_addr_internal(ngx_http_request_t *r, + ngx_addr_t *addr, u_char *xff, size_t xfflen, ngx_array_t *proxies, + int recursive); #if (NGX_HAVE_OPENAT) static char *ngx_http_disable_symlinks(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -1458,11 +1461,7 @@ ngx_http_update_location_config(ngx_http_request_t *r) } if (r == r->main) { - r->connection->log->file = clcf->error_log->file; - - if (!(r->connection->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { - r->connection->log->log_level = clcf->error_log->log_level; - } + ngx_http_set_connection_log(r->connection, clcf->error_log); } if ((ngx_io.flags & NGX_IO_SENDFILE) && clcf->sendfile) { @@ -2747,10 +2746,58 @@ ngx_http_set_disable_symlinks(ngx_http_request_t *r, ngx_int_t ngx_http_get_forwarded_addr(ngx_http_request_t *r, ngx_addr_t *addr, + ngx_array_t *headers, ngx_str_t *value, ngx_array_t *proxies, + int recursive) +{ + ngx_int_t rc; + ngx_uint_t i, found; + ngx_table_elt_t **h; + + if (headers == NULL) { + return ngx_http_get_forwarded_addr_internal(r, addr, value->data, + value->len, proxies, + recursive); + } + + i = headers->nelts; + h = headers->elts; + + rc = NGX_DECLINED; + + found = 0; + + while (i-- > 0) { + rc = ngx_http_get_forwarded_addr_internal(r, addr, h[i]->value.data, + h[i]->value.len, proxies, + recursive); + + if (!recursive) { + break; + } + + if (rc == NGX_DECLINED && found) { + rc = NGX_DONE; + break; + } + + if (rc != NGX_OK) { + break; + } + + found = 1; + } + + return rc; +} + + +static ngx_int_t +ngx_http_get_forwarded_addr_internal(ngx_http_request_t *r, ngx_addr_t *addr, u_char *xff, size_t xfflen, ngx_array_t *proxies, int recursive) { u_char *p; in_addr_t inaddr; + ngx_int_t rc; ngx_addr_t paddr; ngx_cidr_t *cidr; ngx_uint_t family, i; @@ -2842,8 +2889,15 @@ ngx_http_get_forwarded_addr(ngx_http_request_t *r, ngx_addr_t *addr, *addr = paddr; if (recursive && p > xff) { - (void) ngx_http_get_forwarded_addr(r, addr, xff, p - 1 - xff, - proxies, 1); + rc = ngx_http_get_forwarded_addr_internal(r, addr, xff, p - 1 - xff, + proxies, 1); + + if (rc == NGX_DECLINED) { + return NGX_DONE; + } + + /* rc == NGX_OK || rc == NGX_DONE */ + return rc; } return NGX_OK; diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index ff1c2dfa0..921ebbcaa 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -209,6 +209,23 @@ typedef struct { typedef struct { +#if (NGX_PCRE) + ngx_http_regex_t *regex; +#endif + ngx_http_core_srv_conf_t *server; /* virtual name server conf */ + ngx_str_t name; +} ngx_http_server_name_t; + + +typedef struct { + ngx_hash_combined_t names; + + ngx_uint_t nregex; + ngx_http_server_name_t *regex; +} ngx_http_virtual_names_t; + + +struct ngx_http_addr_conf_s { /* the default server configuration for this address:port */ ngx_http_core_srv_conf_t *default_server; @@ -217,7 +234,7 @@ typedef struct { #if (NGX_HTTP_SSL) ngx_uint_t ssl; /* unsigned ssl:1; */ #endif -} ngx_http_addr_conf_t; +}; typedef struct { @@ -268,15 +285,6 @@ typedef struct { } ngx_http_conf_addr_t; -struct ngx_http_server_name_s { -#if (NGX_PCRE) - ngx_http_regex_t *regex; -#endif - ngx_http_core_srv_conf_t *server; /* virtual name server conf */ - ngx_str_t name; -}; - - typedef struct { ngx_int_t status; ngx_int_t overwrite; @@ -516,7 +524,8 @@ ngx_int_t ngx_http_set_disable_symlinks(ngx_http_request_t *r, ngx_http_core_loc_conf_t *clcf, ngx_str_t *path, ngx_open_file_info_t *of); ngx_int_t ngx_http_get_forwarded_addr(ngx_http_request_t *r, ngx_addr_t *addr, - u_char *xff, size_t xfflen, ngx_array_t *proxies, int recursive); + ngx_array_t *headers, ngx_str_t *value, ngx_array_t *proxies, + int recursive); extern ngx_module_t ngx_http_core_module; diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c index bd6cebadd..6d94c5034 100644 --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -1674,8 +1674,6 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) p = (u_char *) ngx_strchr(name.data, ':'); if (p) { - *p = '\0'; - name.len = p - name.data; p++; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 763e7bf11..54e1c262e 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -21,21 +21,24 @@ static ngx_int_t ngx_http_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_process_unique_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t ngx_http_process_multi_header_lines(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_process_host(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_process_user_agent(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); -static ngx_int_t ngx_http_process_cookie(ngx_http_request_t *r, - ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_process_request_header(ngx_http_request_t *r); static void ngx_http_process_request(ngx_http_request_t *r); -static ssize_t ngx_http_validate_host(ngx_http_request_t *r, u_char **host, - size_t len, ngx_uint_t alloc); -static ngx_int_t ngx_http_find_virtual_server(ngx_http_request_t *r, - u_char *host, size_t len); +static ngx_int_t ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool, + ngx_uint_t alloc); +static ngx_int_t ngx_http_set_virtual_server(ngx_http_request_t *r, + ngx_str_t *host); +static ngx_int_t ngx_http_find_virtual_server(ngx_connection_t *c, + ngx_http_virtual_names_t *virtual_names, ngx_str_t *host, + ngx_http_request_t *r, ngx_http_core_srv_conf_t **cscfp); static void ngx_http_request_handler(ngx_event_t *ev); static void ngx_http_terminate_request(ngx_http_request_t *r, ngx_int_t rc); @@ -153,7 +156,7 @@ ngx_http_header_t ngx_http_headers_in[] = { #if (NGX_HTTP_X_FORWARDED_FOR) { ngx_string("X-Forwarded-For"), offsetof(ngx_http_headers_in_t, x_forwarded_for), - ngx_http_process_header_line }, + ngx_http_process_multi_header_lines }, #endif #if (NGX_HTTP_REALIP) @@ -185,7 +188,8 @@ ngx_http_header_t ngx_http_headers_in[] = { ngx_http_process_header_line }, #endif - { ngx_string("Cookie"), 0, ngx_http_process_cookie }, + { ngx_string("Cookie"), offsetof(ngx_http_headers_in_t, cookies), + ngx_http_process_multi_header_lines }, { ngx_null_string, 0, NULL } }; @@ -194,137 +198,30 @@ ngx_http_header_t ngx_http_headers_in[] = { void ngx_http_init_connection(ngx_connection_t *c) { - ngx_event_t *rev; - ngx_http_log_ctx_t *ctx; - - ctx = ngx_palloc(c->pool, sizeof(ngx_http_log_ctx_t)); - if (ctx == NULL) { - ngx_http_close_connection(c); - return; - } - - ctx->connection = c; - ctx->request = NULL; - ctx->current_request = NULL; - - c->log->connection = c->number; - c->log->handler = ngx_http_log_error; - c->log->data = ctx; - c->log->action = "reading client request line"; - - c->log_error = NGX_ERROR_INFO; - - rev = c->read; - rev->handler = ngx_http_init_request; - c->write->handler = ngx_http_empty_handler; - -#if (NGX_STAT_STUB) - (void) ngx_atomic_fetch_add(ngx_stat_reading, 1); -#endif - - if (rev->ready) { - /* the deferred accept(), rtsig, aio, iocp */ - - if (ngx_use_accept_mutex) { - ngx_post_event(rev, &ngx_posted_events); - return; - } - - ngx_http_init_request(rev); - return; - } - - ngx_add_timer(rev, c->listening->post_accept_timeout); - - if (ngx_handle_read_event(rev, 0) != NGX_OK) { -#if (NGX_STAT_STUB) - (void) ngx_atomic_fetch_add(ngx_stat_reading, -1); -#endif - ngx_http_close_connection(c); - return; - } -} - - -static void -ngx_http_init_request(ngx_event_t *rev) -{ - ngx_time_t *tp; - ngx_uint_t i; - ngx_connection_t *c; - ngx_http_request_t *r; - struct sockaddr_in *sin; - ngx_http_port_t *port; - ngx_http_in_addr_t *addr; - ngx_http_log_ctx_t *ctx; - ngx_http_addr_conf_t *addr_conf; - ngx_http_connection_t *hc; - ngx_http_core_srv_conf_t *cscf; - ngx_http_core_loc_conf_t *clcf; - ngx_http_core_main_conf_t *cmcf; + ngx_uint_t i; + ngx_event_t *rev; + struct sockaddr_in *sin; + ngx_http_port_t *port; + ngx_http_in_addr_t *addr; + ngx_http_log_ctx_t *ctx; + ngx_http_connection_t *hc; #if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; - ngx_http_in6_addr_t *addr6; + struct sockaddr_in6 *sin6; + ngx_http_in6_addr_t *addr6; #endif -#if (NGX_STAT_STUB) - (void) ngx_atomic_fetch_add(ngx_stat_reading, -1); -#endif - - c = rev->data; - - if (rev->timedout) { - ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); - + hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t)); + if (hc == NULL) { ngx_http_close_connection(c); return; } - c->requests++; - - hc = c->data; - - if (hc == NULL) { - hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t)); - if (hc == NULL) { - ngx_http_close_connection(c); - return; - } - } - - r = hc->request; - - if (r) { - ngx_memzero(r, sizeof(ngx_http_request_t)); - - r->pipeline = hc->pipeline; - - if (hc->nbusy) { - r->header_in = hc->busy[0]; - } - - } else { - r = ngx_pcalloc(c->pool, sizeof(ngx_http_request_t)); - if (r == NULL) { - ngx_http_close_connection(c); - return; - } - - hc->request = r; - } - - c->data = r; - r->http_connection = hc; - - c->sent = 0; - r->signature = NGX_HTTP_MODULE; + c->data = hc; /* find the server configuration for the address:port */ port = c->listening->servers; - r->connection = c; - if (port->naddrs > 1) { /* @@ -354,7 +251,7 @@ ngx_http_init_request(ngx_event_t *rev) } } - addr_conf = &addr6[i].conf; + hc->addr_conf = &addr6[i].conf; break; #endif @@ -372,7 +269,7 @@ ngx_http_init_request(ngx_event_t *rev) } } - addr_conf = &addr[i].conf; + hc->addr_conf = &addr[i].conf; break; } @@ -384,90 +281,161 @@ ngx_http_init_request(ngx_event_t *rev) #if (NGX_HAVE_INET6) case AF_INET6: addr6 = port->addrs; - addr_conf = &addr6[0].conf; + hc->addr_conf = &addr6[0].conf; break; #endif default: /* AF_INET */ addr = port->addrs; - addr_conf = &addr[0].conf; + hc->addr_conf = &addr[0].conf; break; } } - r->virtual_names = addr_conf->virtual_names; - /* the default server configuration for the address:port */ - cscf = addr_conf->default_server; + hc->conf_ctx = hc->addr_conf->default_server->ctx; - r->main_conf = cscf->ctx->main_conf; - r->srv_conf = cscf->ctx->srv_conf; - r->loc_conf = cscf->ctx->loc_conf; + ctx = ngx_palloc(c->pool, sizeof(ngx_http_log_ctx_t)); + if (ctx == NULL) { + ngx_http_close_connection(c); + return; + } - rev->handler = ngx_http_process_request_line; - r->read_event_handler = ngx_http_block_reading; + ctx->connection = c; + ctx->request = NULL; + ctx->current_request = NULL; -#if (NGX_HTTP_SSL) + c->log->connection = c->number; + c->log->handler = ngx_http_log_error; + c->log->data = ctx; + c->log->action = "reading client request line"; + c->log_error = NGX_ERROR_INFO; + + rev = c->read; + rev->handler = ngx_http_init_request; + c->write->handler = ngx_http_empty_handler; + +#if (NGX_HTTP_SSL) { ngx_http_ssl_srv_conf_t *sscf; - sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); - if (sscf->enable || addr_conf->ssl) { + sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); - if (c->ssl == NULL) { + if (sscf->enable || hc->addr_conf->ssl) { - c->log->action = "SSL handshaking"; + c->log->action = "SSL handshaking"; - if (addr_conf->ssl && sscf->ssl.ctx == NULL) { - ngx_log_error(NGX_LOG_ERR, c->log, 0, - "no \"ssl_certificate\" is defined " - "in server listening on SSL port"); - ngx_http_close_connection(c); - return; - } + if (hc->addr_conf->ssl && sscf->ssl.ctx == NULL) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "no \"ssl_certificate\" is defined " + "in server listening on SSL port"); + ngx_http_close_connection(c); + return; + } - if (ngx_ssl_create_connection(&sscf->ssl, c, NGX_SSL_BUFFER) - != NGX_OK) - { - ngx_http_close_connection(c); - return; - } + hc->ssl = 1; + + rev->handler = ngx_http_ssl_handshake; + } + } +#endif - rev->handler = ngx_http_ssl_handshake; + if (rev->ready) { + /* the deferred accept(), rtsig, aio, iocp */ + + if (ngx_use_accept_mutex) { + ngx_post_event(rev, &ngx_posted_events); + return; } - r->main_filter_need_in_memory = 1; + rev->handler(rev); + return; } + + ngx_add_timer(rev, c->listening->post_accept_timeout); + + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + ngx_http_close_connection(c); + return; } +} -#endif - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - c->log->file = clcf->error_log->file; - if (!(c->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { - c->log->log_level = clcf->error_log->log_level; +static void +ngx_http_init_request(ngx_event_t *rev) +{ + ngx_pool_t *pool; + ngx_time_t *tp; + ngx_connection_t *c; + ngx_http_request_t *r; + ngx_http_log_ctx_t *ctx; + ngx_http_connection_t *hc; + ngx_http_core_srv_conf_t *cscf; + ngx_http_core_loc_conf_t *clcf; + ngx_http_core_main_conf_t *cmcf; + + c = rev->data; + + if (rev->timedout) { + ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); + + ngx_http_close_connection(c); + return; + } + + c->requests++; + + hc = c->data; + + cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_core_module); + + pool = ngx_create_pool(cscf->request_pool_size, c->log); + if (pool == NULL) { + ngx_http_close_connection(c); + return; + } + + r = ngx_pcalloc(pool, sizeof(ngx_http_request_t)); + if (r == NULL) { + ngx_destroy_pool(pool); + ngx_http_close_connection(c); + return; } + r->pool = pool; + + r->pipeline = hc->pipeline; + + c->data = r; + r->http_connection = hc; + + c->sent = 0; + r->signature = NGX_HTTP_MODULE; + + r->connection = c; + + r->main_conf = hc->conf_ctx->main_conf; + r->srv_conf = hc->conf_ctx->srv_conf; + r->loc_conf = hc->conf_ctx->loc_conf; + + r->read_event_handler = ngx_http_block_reading; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + ngx_http_set_connection_log(r->connection, clcf->error_log); + if (c->buffer == NULL) { c->buffer = ngx_create_temp_buf(c->pool, cscf->client_header_buffer_size); if (c->buffer == NULL) { + ngx_destroy_pool(r->pool); ngx_http_close_connection(c); return; } } - if (r->header_in == NULL) { - r->header_in = c->buffer; - } - - r->pool = ngx_create_pool(cscf->request_pool_size, c->log); - if (r->pool == NULL) { - ngx_http_close_connection(c); - return; - } - + r->header_in = hc->nbusy ? hc->busy[0] : c->buffer; if (ngx_list_init(&r->headers_out.headers, r->pool, 20, sizeof(ngx_table_elt_t)) @@ -498,6 +466,12 @@ ngx_http_init_request(ngx_event_t *rev) c->single_connection = 1; c->destroyed = 0; +#if (NGX_HTTP_SSL) + if (c->ssl) { + r->main_filter_need_in_memory = 1; + } +#endif + r->main = r; r->count = 1; @@ -528,7 +502,8 @@ ngx_http_init_request(ngx_event_t *rev) (void) ngx_atomic_fetch_add(ngx_stat_requests, 1); #endif - rev->handler(rev); + rev->handler = ngx_http_process_request_line; + ngx_http_process_request_line(rev); } @@ -537,37 +512,48 @@ ngx_http_init_request(ngx_event_t *rev) static void ngx_http_ssl_handshake(ngx_event_t *rev) { - u_char buf[1]; - ssize_t n; - ngx_int_t rc; - ngx_connection_t *c; - ngx_http_request_t *r; + u_char buf[1]; + ssize_t n; + ngx_err_t err; + ngx_int_t rc; + ngx_connection_t *c; + ngx_http_connection_t *hc; + ngx_http_ssl_srv_conf_t *sscf; c = rev->data; - r = c->data; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http check ssl handshake"); if (rev->timedout) { ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); - c->timedout = 1; - ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT); + ngx_http_close_connection(c); return; } n = recv(c->fd, (char *) buf, 1, MSG_PEEK); - if (n == -1 && ngx_socket_errno == NGX_EAGAIN) { + err = ngx_socket_errno; - if (!rev->timer_set) { - ngx_add_timer(rev, c->listening->post_accept_timeout); - } + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http recv(): %d", n); - if (ngx_handle_read_event(rev, 0) != NGX_OK) { - ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + if (n == -1) { + if (err == NGX_EAGAIN) { + + if (!rev->timer_set) { + ngx_add_timer(rev, c->listening->post_accept_timeout); + } + + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + ngx_http_close_connection(c); + } + + return; } + ngx_connection_error(c, err, "recv() failed"); + ngx_http_close_connection(c); + return; } @@ -576,6 +562,17 @@ ngx_http_ssl_handshake(ngx_event_t *rev) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0, "https ssl handshake: 0x%02Xd", buf[0]); + hc = c->data; + sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, + ngx_http_ssl_module); + + if (ngx_ssl_create_connection(&sscf->ssl, c, NGX_SSL_BUFFER) + != NGX_OK) + { + ngx_http_close_connection(c); + return; + } + rc = ngx_ssl_handshake(c); if (rc == NGX_AGAIN) { @@ -591,27 +588,26 @@ ngx_http_ssl_handshake(ngx_event_t *rev) ngx_http_ssl_handshake_handler(c); return; + } - } else { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, - "plain http"); + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "plain http"); - r->plain_http = 1; - } - } + c->log->action = "reading client request line"; - c->log->action = "reading client request line"; + rev->handler = ngx_http_init_request; + ngx_http_init_request(rev); - rev->handler = ngx_http_process_request_line; - ngx_http_process_request_line(rev); + return; + } + + ngx_log_error(NGX_LOG_INFO, c->log, 0, "client closed connection"); + ngx_http_close_connection(c); } static void ngx_http_ssl_handshake_handler(ngx_connection_t *c) { - ngx_http_request_t *r; - if (c->ssl->handshaked) { /* @@ -626,19 +622,19 @@ ngx_http_ssl_handshake_handler(ngx_connection_t *c) c->log->action = "reading client request line"; - c->read->handler = ngx_http_process_request_line; + c->read->handler = ngx_http_init_request; /* STUB: epoll edge */ c->write->handler = ngx_http_empty_handler; - ngx_http_process_request_line(c->read); + ngx_http_init_request(c->read); return; } - r = c->data; - - ngx_http_close_request(r, NGX_HTTP_BAD_REQUEST); + if (c->read->timedout) { + ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); + } - return; + ngx_http_close_connection(c); } #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME @@ -646,12 +642,13 @@ ngx_http_ssl_handshake_handler(ngx_connection_t *c) int ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) { - size_t len; - u_char *host; - const char *servername; - ngx_connection_t *c; - ngx_http_request_t *r; - ngx_http_ssl_srv_conf_t *sscf; + ngx_str_t host; + const char *servername; + ngx_connection_t *c; + ngx_http_connection_t *hc; + ngx_http_ssl_srv_conf_t *sscf; + ngx_http_core_loc_conf_t *clcf; + ngx_http_core_srv_conf_t *cscf; servername = SSL_get_servername(ssl_conn, TLSEXT_NAMETYPE_host_name); @@ -664,27 +661,41 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "SSL server name: \"%s\"", servername); - len = ngx_strlen(servername); + host.len = ngx_strlen(servername); - if (len == 0) { + if (host.len == 0) { return SSL_TLSEXT_ERR_NOACK; } - r = c->data; + host.data = (u_char *) servername; - host = (u_char *) servername; + if (ngx_http_validate_host(&host, c->pool, 1) != NGX_OK) { + return SSL_TLSEXT_ERR_NOACK; + } - len = ngx_http_validate_host(r, &host, len, 1); + hc = c->data; - if (len <= 0) { + if (ngx_http_find_virtual_server(c, hc->addr_conf->virtual_names, &host, + NULL, &cscf) + != NGX_OK) + { return SSL_TLSEXT_ERR_NOACK; } - if (ngx_http_find_virtual_server(r, host, len) != NGX_OK) { + hc->ssl_servername = ngx_palloc(c->pool, sizeof(ngx_str_t)); + if (hc->ssl_servername == NULL) { return SSL_TLSEXT_ERR_NOACK; } - sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); + *hc->ssl_servername = host; + + hc->conf_ctx = cscf->ctx; + + clcf = ngx_http_get_module_loc_conf(hc->conf_ctx, ngx_http_core_module); + + ngx_http_set_connection_log(c, clcf->error_log); + + sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); if (sscf->ssl.ctx) { SSL_set_SSL_CTX(ssl_conn, sscf->ssl.ctx); @@ -719,9 +730,9 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) static void ngx_http_process_request_line(ngx_event_t *rev) { - u_char *host; ssize_t n; ngx_int_t rc, rv; + ngx_str_t host; ngx_connection_t *c; ngx_http_request_t *r; ngx_http_core_srv_conf_t *cscf; @@ -887,33 +898,36 @@ ngx_http_process_request_line(ngx_event_t *rev) if (r->host_start && r->host_end) { - host = r->host_start; - n = ngx_http_validate_host(r, &host, - r->host_end - r->host_start, 0); + host.len = r->host_end - r->host_start; + host.data = r->host_start; + + rc = ngx_http_validate_host(&host, r->pool, 0); - if (n == 0) { + if (rc == NGX_DECLINED) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "client sent invalid host in request line"); ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); return; } - if (n < 0) { + if (rc == NGX_ERROR) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } - r->headers_in.server.len = n; - r->headers_in.server.data = host; + if (ngx_http_set_virtual_server(r, &host) == NGX_ERROR) { + return; + } + + r->headers_in.server = host; } if (r->http_version < NGX_HTTP_VERSION_10) { - if (ngx_http_find_virtual_server(r, r->headers_in.server.data, - r->headers_in.server.len) - == NGX_ERROR) + if (r->headers_in.server.len == 0 + && ngx_http_set_virtual_server(r, &r->headers_in.server) + == NGX_ERROR) { - ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } @@ -930,15 +944,6 @@ ngx_http_process_request_line(ngx_event_t *rev) return; } - - if (ngx_array_init(&r->headers_in.cookies, r->pool, 2, - sizeof(ngx_table_elt_t *)) - != NGX_OK) - { - ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - c->log->action = "reading client request headers"; rev->handler = ngx_http_process_request_headers; @@ -1010,7 +1015,6 @@ ngx_http_process_request_headers(ngx_event_t *rev) } cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); - cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); rc = NGX_AGAIN; @@ -1064,6 +1068,9 @@ ngx_http_process_request_headers(ngx_event_t *rev) } } + /* the host header could change the server configuration context */ + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + rc = ngx_http_parse_header_line(r, r->header_in, cscf->underscores_in_headers); @@ -1413,24 +1420,25 @@ static ngx_int_t ngx_http_process_host(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { - u_char *host; - ssize_t len; + ngx_int_t rc; + ngx_str_t host; if (r->headers_in.host == NULL) { r->headers_in.host = h; } - host = h->value.data; - len = ngx_http_validate_host(r, &host, h->value.len, 0); + host = h->value; + + rc = ngx_http_validate_host(&host, r->pool, 0); - if (len == 0) { + if (rc == NGX_DECLINED) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "client sent invalid host header"); ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); return NGX_ERROR; } - if (len < 0) { + if (rc == NGX_ERROR) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return NGX_ERROR; } @@ -1439,8 +1447,11 @@ ngx_http_process_host(ngx_http_request_t *r, ngx_table_elt_t *h, return NGX_OK; } - r->headers_in.server.len = len; - r->headers_in.server.data = host; + if (ngx_http_set_virtual_server(r, &host) == NGX_ERROR) { + return NGX_ERROR; + } + + r->headers_in.server = host; return NGX_OK; } @@ -1535,31 +1546,41 @@ ngx_http_process_user_agent(ngx_http_request_t *r, ngx_table_elt_t *h, static ngx_int_t -ngx_http_process_cookie(ngx_http_request_t *r, ngx_table_elt_t *h, +ngx_http_process_multi_header_lines(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { - ngx_table_elt_t **cookie; + ngx_array_t *headers; + ngx_table_elt_t **ph; - cookie = ngx_array_push(&r->headers_in.cookies); - if (cookie) { - *cookie = h; - return NGX_OK; + headers = (ngx_array_t *) ((char *) &r->headers_in + offset); + + if (headers->elts == NULL) { + if (ngx_array_init(headers, r->pool, 1, sizeof(ngx_table_elt_t *)) + != NGX_OK) + { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_ERROR; + } } - ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + ph = ngx_array_push(headers); + if (ph == NULL) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_ERROR; + } - return NGX_ERROR; + *ph = h; + return NGX_OK; } static ngx_int_t ngx_http_process_request_header(ngx_http_request_t *r) { - if (ngx_http_find_virtual_server(r, r->headers_in.server.data, - r->headers_in.server.len) - == NGX_ERROR) + if (r->headers_in.server.len == 0 + && ngx_http_set_virtual_server(r, &r->headers_in.server) + == NGX_ERROR) { - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return NGX_ERROR; } @@ -1630,20 +1651,20 @@ ngx_http_process_request(ngx_http_request_t *r) c = r->connection; - if (r->plain_http) { - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client sent plain HTTP request to HTTPS port"); - ngx_http_finalize_request(r, NGX_HTTP_TO_HTTPS); - return; - } - #if (NGX_HTTP_SSL) - if (c->ssl) { + if (r->http_connection->ssl) { long rc; X509 *cert; ngx_http_ssl_srv_conf_t *sscf; + if (c->ssl == NULL) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent plain HTTP request to HTTPS port"); + ngx_http_finalize_request(r, NGX_HTTP_TO_HTTPS); + return; + } + sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); if (sscf->verify) { @@ -1705,9 +1726,8 @@ ngx_http_process_request(ngx_http_request_t *r) } -static ssize_t -ngx_http_validate_host(ngx_http_request_t *r, u_char **host, size_t len, - ngx_uint_t alloc) +static ngx_int_t +ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool, ngx_uint_t alloc) { u_char *h, ch; size_t i, dot_pos, host_len; @@ -1718,21 +1738,21 @@ ngx_http_validate_host(ngx_http_request_t *r, u_char **host, size_t len, sw_rest } state; - dot_pos = len; - host_len = len; + dot_pos = host->len; + host_len = host->len; - h = *host; + h = host->data; state = sw_usual; - for (i = 0; i < len; i++) { + for (i = 0; i < host->len; i++) { ch = h[i]; switch (ch) { case '.': if (dot_pos == i - 1) { - return 0; + return NGX_DECLINED; } dot_pos = i; break; @@ -1758,12 +1778,12 @@ ngx_http_validate_host(ngx_http_request_t *r, u_char **host, size_t len, break; case '\0': - return 0; + return NGX_DECLINED; default: if (ngx_path_separator(ch)) { - return 0; + return NGX_DECLINED; } if (ch >= 'A' && ch <= 'Z') { @@ -1778,83 +1798,187 @@ ngx_http_validate_host(ngx_http_request_t *r, u_char **host, size_t len, host_len--; } + if (host_len == 0) { + return NGX_DECLINED; + } + if (alloc) { - *host = ngx_pnalloc(r->pool, host_len); - if (*host == NULL) { - return -1; + host->data = ngx_pnalloc(pool, host_len); + if (host->data == NULL) { + return NGX_ERROR; } - ngx_strlow(*host, h, host_len); + ngx_strlow(host->data, h, host_len); } - return host_len; + host->len = host_len; + + return NGX_OK; } static ngx_int_t -ngx_http_find_virtual_server(ngx_http_request_t *r, u_char *host, size_t len) +ngx_http_set_virtual_server(ngx_http_request_t *r, ngx_str_t *host) { + ngx_int_t rc; + ngx_http_connection_t *hc; ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; - if (r->virtual_names == NULL) { + hc = r->http_connection; + +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + + if (hc->ssl_servername) { + if (hc->ssl_servername->len == host->len + && ngx_strncmp(hc->ssl_servername->data, + host->data, host->len) == 0) + { +#if (NGX_PCRE) + if (hc->ssl_servername_regex + && ngx_http_regex_exec(r, hc->ssl_servername_regex, + hc->ssl_servername) != NGX_OK) + { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_ERROR; + } +#endif + return NGX_OK; + } + } + +#endif + + rc = ngx_http_find_virtual_server(r->connection, + hc->addr_conf->virtual_names, + host, r, &cscf); + + if (rc == NGX_ERROR) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_ERROR; + } + +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + + if (hc->ssl_servername) { + ngx_http_ssl_srv_conf_t *sscf; + + if (rc == NGX_DECLINED) { + cscf = hc->addr_conf->default_server; + rc = NGX_OK; + } + + sscf = ngx_http_get_module_srv_conf(cscf->ctx, ngx_http_ssl_module); + + if (sscf->verify) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client attempted to request the server name " + "different from that one was negotiated"); + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return NGX_ERROR; + } + } + +#endif + + if (rc == NGX_DECLINED) { + return NGX_OK; + } + + r->srv_conf = cscf->ctx->srv_conf; + r->loc_conf = cscf->ctx->loc_conf; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + ngx_http_set_connection_log(r->connection, clcf->error_log); + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_find_virtual_server(ngx_connection_t *c, + ngx_http_virtual_names_t *virtual_names, ngx_str_t *host, + ngx_http_request_t *r, ngx_http_core_srv_conf_t **cscfp) +{ + ngx_http_core_srv_conf_t *cscf; + + if (virtual_names == NULL) { return NGX_DECLINED; } - cscf = ngx_hash_find_combined(&r->virtual_names->names, - ngx_hash_key(host, len), host, len); + cscf = ngx_hash_find_combined(&virtual_names->names, + ngx_hash_key(host->data, host->len), + host->data, host->len); if (cscf) { - goto found; + *cscfp = cscf; + return NGX_OK; } #if (NGX_PCRE) - if (len && r->virtual_names->nregex) { + if (host->len && virtual_names->nregex) { ngx_int_t n; ngx_uint_t i; - ngx_str_t name; ngx_http_server_name_t *sn; - name.len = len; - name.data = host; + sn = virtual_names->regex; - sn = r->virtual_names->regex; +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME - for (i = 0; i < r->virtual_names->nregex; i++) { + if (r == NULL) { + ngx_http_connection_t *hc; - n = ngx_http_regex_exec(r, sn[i].regex, &name); + for (i = 0; i < virtual_names->nregex; i++) { - if (n == NGX_OK) { - cscf = sn[i].server; - goto found; - } + n = ngx_regex_exec(sn[i].regex->regex, host, NULL, 0); - if (n == NGX_DECLINED) { - continue; + if (n == NGX_REGEX_NO_MATCHED) { + continue; + } + + if (n >= 0) { + hc = c->data; + hc->ssl_servername_regex = sn[i].regex; + + *cscfp = sn[i].server; + return NGX_OK; + } + + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + ngx_regex_exec_n " failed: %i " + "on \"%V\" using \"%V\"", + n, host, &sn[i].regex->name); + + return NGX_ERROR; } - return NGX_ERROR; + return NGX_DECLINED; } - } -#endif +#endif /* SSL_CTRL_SET_TLSEXT_HOSTNAME */ - return NGX_DECLINED; + for (i = 0; i < virtual_names->nregex; i++) { -found: + n = ngx_http_regex_exec(r, sn[i].regex, host); - r->srv_conf = cscf->ctx->srv_conf; - r->loc_conf = cscf->ctx->loc_conf; + if (n == NGX_DECLINED) { + continue; + } - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - r->connection->log->file = clcf->error_log->file; + if (n == NGX_OK) { + *cscfp = sn[i].server; + return NGX_OK; + } - if (!(r->connection->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { - r->connection->log->log_level = clcf->error_log->log_level; + return NGX_ERROR; + } } - return NGX_OK; +#endif /* NGX_PCRE */ + + return NGX_DECLINED; } @@ -2528,6 +2652,7 @@ ngx_http_set_keepalive(ngx_http_request_t *r) } } + /* guard against recursive call from ngx_http_finalize_connection() */ r->keepalive = 0; ngx_http_free_request(r, 0); @@ -2548,10 +2673,6 @@ ngx_http_set_keepalive(ngx_http_request_t *r) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "pipelined request"); -#if (NGX_STAT_STUB) - (void) ngx_atomic_fetch_add(ngx_stat_reading, 1); -#endif - hc->pipeline = 1; c->log->action = "reading client pipelined request line"; @@ -2563,17 +2684,12 @@ ngx_http_set_keepalive(ngx_http_request_t *r) hc->pipeline = 0; /* - * To keep a memory footprint as small as possible for an idle - * keepalive connection we try to free the ngx_http_request_t and - * c->buffer's memory if they were allocated outside the c->pool. - * The large header buffers are always allocated outside the c->pool and - * are freed too. + * To keep a memory footprint as small as possible for an idle keepalive + * connection we try to free c->buffer's memory if it was allocated outside + * the c->pool. The large header buffers are always allocated outside the + * c->pool and are freed too. */ - if (ngx_pfree(c->pool, r) == NGX_OK) { - hc->request = NULL; - } - b = c->buffer; if (ngx_pfree(c->pool, b->start) == NGX_OK) { @@ -2758,6 +2874,7 @@ ngx_http_keepalive_handler(ngx_event_t *rev) if (n == NGX_AGAIN) { if (ngx_handle_read_event(rev, 0) != NGX_OK) { ngx_http_close_connection(c); + return; } /* @@ -2793,10 +2910,6 @@ ngx_http_keepalive_handler(ngx_event_t *rev) b->last += n; -#if (NGX_STAT_STUB) - (void) ngx_atomic_fetch_add(ngx_stat_reading, 1); -#endif - c->log->handler = ngx_http_log_error; c->log->action = "reading client request line"; @@ -3027,6 +3140,7 @@ static void ngx_http_free_request(ngx_http_request_t *r, ngx_int_t rc) { ngx_log_t *log; + ngx_pool_t *pool; struct linger linger; ngx_http_cleanup_t *cln; ngx_http_log_ctx_t *ctx; @@ -3093,7 +3207,15 @@ ngx_http_free_request(ngx_http_request_t *r, ngx_int_t rc) r->connection->destroyed = 1; - ngx_destroy_pool(r->pool); + /* + * Setting r->pool to NULL will increase probability to catch double close + * of request since the request object is allocated from its own pool. + */ + + pool = r->pool; + r->pool = NULL; + + ngx_destroy_pool(pool); } diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index f0c39adaf..fd004e8f1 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -200,7 +200,7 @@ typedef struct { ngx_table_elt_t *keep_alive; #if (NGX_HTTP_X_FORWARDED_FOR) - ngx_table_elt_t *x_forwarded_for; + ngx_array_t x_forwarded_for; #endif #if (NGX_HTTP_REALIP) @@ -289,8 +289,18 @@ typedef struct { } ngx_http_request_body_t; +typedef struct ngx_http_addr_conf_s ngx_http_addr_conf_t; + typedef struct { - ngx_http_request_t *request; + ngx_http_addr_conf_t *addr_conf; + ngx_http_conf_ctx_t *conf_ctx; + +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + ngx_str_t *ssl_servername; +#if (NGX_PCRE) + ngx_http_regex_t *ssl_servername_regex; +#endif +#endif ngx_buf_t **busy; ngx_int_t nbusy; @@ -298,21 +308,11 @@ typedef struct { ngx_buf_t **free; ngx_int_t nfree; - ngx_uint_t pipeline; /* unsigned pipeline:1; */ + unsigned pipeline:1; + unsigned ssl:1; } ngx_http_connection_t; -typedef struct ngx_http_server_name_s ngx_http_server_name_t; - - -typedef struct { - ngx_hash_combined_t names; - - ngx_uint_t nregex; - ngx_http_server_name_t *regex; -} ngx_http_virtual_names_t; - - typedef void (*ngx_http_cleanup_pt)(void *data); typedef struct ngx_http_cleanup_s ngx_http_cleanup_t; @@ -406,8 +406,6 @@ struct ngx_http_request_s { ngx_http_post_subrequest_t *post_subrequest; ngx_http_posted_request_t *posted_requests; - ngx_http_virtual_names_t *virtual_names; - ngx_int_t phase_handler; ngx_http_handler_pt content_handler; ngx_uint_t access_code; @@ -500,7 +498,6 @@ struct ngx_http_request_s { #endif unsigned pipeline:1; - unsigned plain_http:1; unsigned chunked:1; unsigned header_only:1; unsigned keepalive:1; @@ -580,4 +577,12 @@ extern ngx_http_header_t ngx_http_headers_in[]; extern ngx_http_header_out_t ngx_http_headers_out[]; +#define ngx_http_set_connection_log(c, l) \ + \ + c->log->file = l->file; \ + if (!(c->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { \ + c->log->log_level = l->log_level; \ + } + + #endif /* _NGX_HTTP_REQUEST_H_INCLUDED_ */ diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c index b8190b030..6f1e0344d 100644 --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -21,8 +21,13 @@ static void ngx_http_variable_request_set_size(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_header(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); + +static ngx_int_t ngx_http_variable_cookies(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_headers(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_headers_internal(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data, u_char sep); static ngx_int_t ngx_http_variable_unknown_header_in(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); @@ -133,8 +138,8 @@ static ngx_int_t ngx_http_variable_time_local(ngx_http_request_t *r, */ /* - * the $http_host, $http_user_agent, $http_referer, $http_via, - * and $http_x_forwarded_for variables may be handled by generic + * the $http_host, $http_user_agent, $http_referer, and $http_via + * variables may be handled by generic * ngx_http_variable_unknown_header_in(), but for performance reasons * they are handled using dedicated entries */ @@ -156,11 +161,11 @@ static ngx_http_variable_t ngx_http_core_variables[] = { #endif #if (NGX_HTTP_X_FORWARDED_FOR) - { ngx_string("http_x_forwarded_for"), NULL, ngx_http_variable_header, + { ngx_string("http_x_forwarded_for"), NULL, ngx_http_variable_headers, offsetof(ngx_http_request_t, headers_in.x_forwarded_for), 0, 0 }, #endif - { ngx_string("http_cookie"), NULL, ngx_http_variable_headers, + { ngx_string("http_cookie"), NULL, ngx_http_variable_cookies, offsetof(ngx_http_request_t, headers_in.cookies), 0, 0 }, { ngx_string("content_length"), NULL, ngx_http_variable_content_length, @@ -726,8 +731,24 @@ ngx_http_variable_header(ngx_http_request_t *r, ngx_http_variable_value_t *v, static ngx_int_t -ngx_http_variable_headers(ngx_http_request_t *r, ngx_http_variable_value_t *v, - uintptr_t data) +ngx_http_variable_cookies(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + return ngx_http_variable_headers_internal(r, v, data, ';'); +} + + +static ngx_int_t +ngx_http_variable_headers(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + return ngx_http_variable_headers_internal(r, v, data, ','); +} + + +static ngx_int_t +ngx_http_variable_headers_internal(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data, u_char sep) { size_t len; u_char *p, *end; @@ -748,7 +769,7 @@ ngx_http_variable_headers(ngx_http_request_t *r, ngx_http_variable_value_t *v, continue; } - len += h[i]->value.len + sizeof("; ") - 1; + len += h[i]->value.len + 2; } if (len == 0) { @@ -756,7 +777,7 @@ ngx_http_variable_headers(ngx_http_request_t *r, ngx_http_variable_value_t *v, return NGX_OK; } - len -= sizeof("; ") - 1; + len -= 2; v->valid = 1; v->no_cacheable = 0; @@ -791,7 +812,7 @@ ngx_http_variable_headers(ngx_http_request_t *r, ngx_http_variable_value_t *v, break; } - *p++ = ';'; *p++ = ' '; + *p++ = sep; *p++ = ' '; } return NGX_OK; |