diff options
author | nginx <nginx@nginx.org> | 2014-03-04 15:19:17 +0000 |
---|---|---|
committer | Jon Kolb <kolbyjack@gmail.com> | 2014-03-04 15:19:17 +0000 |
commit | 433c60ea060aa4be99c69bde2eda030f920c97ee (patch) | |
tree | d31cc567211ca28064df284a70c46ee8eec4ef3b | |
parent | 7906d14d074d8ba13d3a5fe767bfd563a922c687 (diff) | |
download | nginx-433c60ea060aa4be99c69bde2eda030f920c97ee.tar.gz |
Changes with nginx 1.5.11 04 Mar 2014v1.5.11
*) Security: memory corruption might occur in a worker process on 32-bit
platforms while handling a specially crafted request by
ngx_http_spdy_module, potentially resulting in arbitrary code
execution (CVE-2014-0088); the bug had appeared in 1.5.10.
Thanks to Lucas Molas, researcher at Programa STIC, Fundación Dr.
Manuel Sadosky, Buenos Aires, Argentina.
*) Feature: the $ssl_session_reused variable.
*) Bugfix: the "client_max_body_size" directive might not work when
reading a request body using chunked transfer encoding; the bug had
appeared in 1.3.9.
Thanks to Lucas Molas.
*) Bugfix: a segmentation fault might occur in a worker process when
proxying WebSocket connections.
*) Bugfix: a segmentation fault might occur in a worker process if the
ngx_http_spdy_module was used on 32-bit platforms; the bug had
appeared in 1.5.10.
*) Bugfix: the $upstream_status variable might contain wrong data if the
"proxy_cache_use_stale" or "proxy_cache_revalidate" directives were
used.
Thanks to Piotr Sikora.
*) Bugfix: a segmentation fault might occur in a worker process if
errors with code 400 were redirected to a named location using the
"error_page" directive.
*) Bugfix: nginx/Windows could not be built with Visual Studio 2013.
26 files changed, 188 insertions, 79 deletions
@@ -1,4 +1,39 @@ +Changes with nginx 1.5.11 04 Mar 2014 + + *) Security: memory corruption might occur in a worker process on 32-bit + platforms while handling a specially crafted request by + ngx_http_spdy_module, potentially resulting in arbitrary code + execution (CVE-2014-0088); the bug had appeared in 1.5.10. + Thanks to Lucas Molas, researcher at Programa STIC, Fundación Dr. + Manuel Sadosky, Buenos Aires, Argentina. + + *) Feature: the $ssl_session_reused variable. + + *) Bugfix: the "client_max_body_size" directive might not work when + reading a request body using chunked transfer encoding; the bug had + appeared in 1.3.9. + Thanks to Lucas Molas. + + *) Bugfix: a segmentation fault might occur in a worker process when + proxying WebSocket connections. + + *) Bugfix: a segmentation fault might occur in a worker process if the + ngx_http_spdy_module was used on 32-bit platforms; the bug had + appeared in 1.5.10. + + *) Bugfix: the $upstream_status variable might contain wrong data if the + "proxy_cache_use_stale" or "proxy_cache_revalidate" directives were + used. + Thanks to Piotr Sikora. + + *) Bugfix: a segmentation fault might occur in a worker process if + errors with code 400 were redirected to a named location using the + "error_page" directive. + + *) Bugfix: nginx/Windows could not be built with Visual Studio 2013. + + Changes with nginx 1.5.10 04 Feb 2014 *) Feature: the ngx_http_spdy_module now uses SPDY 3.1 protocol. diff --git a/CHANGES.ru b/CHANGES.ru index 006b364a5..2d79bee66 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,40 @@ +Изменения в nginx 1.5.11 04.03.2014 + + *) Безопасность: при обработке специально созданного запроса модулем + ngx_http_spdy_module на 32-битных платформах могла повреждаться + память рабочего процесса, что потенциально могло приводить к + выполнению произвольного кода (CVE-2014-0088); ошибка появилась в + 1.5.10. + Спасибо Lucas Molas из Programa STIC, Fundación Dr. Manuel Sadosky, + Buenos Aires, Argentina. + + *) Добавление: переменная $ssl_session_reused. + + *) Исправление: директива client_max_body_size могла не работать при + чтении тела запроса с использованием chunked transfer encoding; + ошибка появилась в 1.3.9. + Спасибо Lucas Molas. + + *) Исправление: при проксировании WebSocket-соединений в рабочем + процессе мог произойти segmentation fault. + + *) Исправление: в рабочем процессе мог произойти segmentation fault, + если использовался модуль ngx_http_spdy_module на 32-битных + платформах; ошибка появилась в 1.5.10. + + *) Исправление: значение переменной $upstream_status могло быть + неверным, если использовались директивы proxy_cache_use_stale или + proxy_cache_revalidate. + Спасибо Piotr Sikora. + + *) Исправление: в рабочем процессе мог произойти segmentation fault, + если ошибки с кодом 400 с помощью директивы error_page + перенаправлялись в именованный location. + + *) Исправление: nginx/Windows не собирался с Visual Studio 2013. + + Изменения в nginx 1.5.10 04.02.2014 *) Добавление: модуль ngx_http_spdy_module теперь использует протокол diff --git a/auto/cc/msvc b/auto/cc/msvc index 1bf675e19..6cb8b3d58 100644 --- a/auto/cc/msvc +++ b/auto/cc/msvc @@ -106,6 +106,7 @@ fi # precompiled headers CORE_DEPS="$CORE_DEPS $NGX_OBJS/ngx_config.pch" +CORE_LINK="$NGX_OBJS/ngx_pch.obj" NGX_PCH="$NGX_OBJS/ngx_config.pch" NGX_BUILD_PCH="-Ycngx_config.h -Fp$NGX_OBJS/ngx_config.pch" NGX_USE_PCH="-Yungx_config.h -Fp$NGX_OBJS/ngx_config.pch" diff --git a/src/core/nginx.h b/src/core/nginx.h index 71a71230c..8ab0e8890 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1005010 -#define NGINX_VERSION "1.5.10" +#define nginx_version 1005011 +#define NGINX_VERSION "1.5.11" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index 15f4f3c90..6b6e3b3a5 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -129,7 +129,7 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) #if (NGX_HAVE_INET6) case AF_INET6: ls[i].addr_text_max_len = NGX_INET6_ADDRSTRLEN; - len = NGX_INET6_ADDRSTRLEN + sizeof(":65535") - 1; + len = NGX_INET6_ADDRSTRLEN + sizeof("[]:65535") - 1; break; #endif @@ -244,7 +244,7 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) if (getsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER, &af, &olen) == -1) { - err = ngx_errno; + err = ngx_socket_errno; if (err == NGX_EINVAL) { continue; @@ -277,7 +277,7 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) if (getsockopt(ls[i].fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, &olen) == -1) { - err = ngx_errno; + err = ngx_socket_errno; if (err == NGX_EOPNOTSUPP) { continue; @@ -661,7 +661,7 @@ ngx_configure_listening_sockets(ngx_cycle_t *cycle) if (setsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER, NULL, 0) == -1) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, "setsockopt(SO_ACCEPTFILTER, NULL) " "for %V failed, ignored", &ls[i].addr_text); @@ -688,7 +688,7 @@ ngx_configure_listening_sockets(ngx_cycle_t *cycle) &af, sizeof(struct accept_filter_arg)) == -1) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, "setsockopt(SO_ACCEPTFILTER, \"%s\") " "for %V failed, ignored", ls[i].accept_filter, &ls[i].addr_text); @@ -721,7 +721,7 @@ ngx_configure_listening_sockets(ngx_cycle_t *cycle) &value, sizeof(int)) == -1) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, "setsockopt(TCP_DEFER_ACCEPT, %d) for %V failed, " "ignored", value, &ls[i].addr_text); diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c index abf82d85b..7fab50abc 100644 --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -3037,14 +3037,7 @@ ngx_udp_connect(ngx_udp_connection_t *uc) ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno, ngx_nonblocking_n " failed"); - ngx_free_connection(c); - - if (ngx_close_socket(s) == -1) { - ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno, - ngx_close_socket_n " failed"); - } - - return NGX_ERROR; + goto failed; } rev = c->read; @@ -3079,7 +3072,7 @@ ngx_udp_connect(ngx_udp_connection_t *uc) ngx_log_error(NGX_LOG_CRIT, &uc->log, ngx_socket_errno, "connect() failed"); - return NGX_ERROR; + goto failed; } /* UDP sockets are always ready to write */ @@ -3093,16 +3086,23 @@ ngx_udp_connect(ngx_udp_connection_t *uc) /* eventport event type has no meaning: oneshot only */ if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) { - return NGX_ERROR; + goto failed; } } else { /* rtsig */ if (ngx_add_conn(c) == NGX_ERROR) { - return NGX_ERROR; + goto failed; } } return NGX_OK; + +failed: + + ngx_close_connection(c); + uc->connection = NULL; + + return NGX_ERROR; } diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index cbe4136a1..28e7aa509 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -2529,6 +2529,20 @@ ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) ngx_int_t +ngx_ssl_get_session_reused(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ + if (SSL_session_reused(c->ssl->connection)) { + ngx_str_set(s, "r"); + + } else { + ngx_str_set(s, "."); + } + + return NGX_OK; +} + + +ngx_int_t ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) { size_t len; diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index 907639e83..b7f850019 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -157,6 +157,8 @@ ngx_int_t ngx_ssl_get_cipher_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); +ngx_int_t ngx_ssl_get_session_reused(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); ngx_int_t ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_certificate(ngx_connection_t *c, ngx_pool_t *pool, diff --git a/src/http/modules/ngx_http_access_module.c b/src/http/modules/ngx_http_access_module.c index fcee40ca0..c553e4610 100644 --- a/src/http/modules/ngx_http_access_module.c +++ b/src/http/modules/ngx_http_access_module.c @@ -259,7 +259,11 @@ ngx_http_access_unix(ngx_http_request_t *r, ngx_http_access_loc_conf_t *alcf) rule_un = alcf->rules_un->elts; for (i = 0; i < alcf->rules_un->nelts; i++) { - return ngx_http_access_found(r, rule_un[i].deny); + + /* TODO: check path */ + if (1) { + return ngx_http_access_found(r, rule_un[i].deny); + } } return NGX_DECLINED; diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index 5bcf6ef8c..24dbbf663 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -1584,7 +1584,7 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) ngx_str_set(&u->headers_in.status_line, "200 OK"); } - if (u->state) { + if (u->state && u->state->status == 0) { u->state->status = u->headers_in.status_n; } diff --git a/src/http/modules/ngx_http_gzip_static_module.c b/src/http/modules/ngx_http_gzip_static_module.c index 6e777619b..1746e5504 100644 --- a/src/http/modules/ngx_http_gzip_static_module.c +++ b/src/http/modules/ngx_http_gzip_static_module.c @@ -38,7 +38,7 @@ static ngx_conf_enum_t ngx_http_gzip_static[] = { static ngx_command_t ngx_http_gzip_static_commands[] = { { ngx_string("gzip_static"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_enum_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_gzip_static_conf_t, enable), diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c index c29ab1ce5..426a0b97f 100644 --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -2481,7 +2481,7 @@ ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4, n = (next_chunk - chunk) * samples; - if (start_sample <= n) { + if (start_sample < n) { goto found; } diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 93469984c..8ee32f491 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -1362,7 +1362,7 @@ ngx_http_proxy_process_status_line(ngx_http_request_t *r) return NGX_OK; } - if (u->state) { + if (u->state && u->state->status == 0) { u->state->status = ctx->status.code; } diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c index 6143a8786..bcc64fd30 100644 --- a/src/http/modules/ngx_http_range_filter_module.c +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -432,7 +432,9 @@ ngx_http_range_multipart_header(ngx_http_request_t *r, + r->headers_out.content_type.len + sizeof(CRLF "Content-Range: bytes ") - 1; - if (r->headers_out.charset.len) { + if (r->headers_out.content_type_len == r->headers_out.content_type.len + && r->headers_out.charset.len) + { len += sizeof("; charset=") - 1 + r->headers_out.charset.len; } @@ -451,7 +453,9 @@ ngx_http_range_multipart_header(ngx_http_request_t *r, * "Content-Range: bytes " */ - if (r->headers_out.charset.len) { + if (r->headers_out.content_type_len == r->headers_out.content_type.len + && r->headers_out.charset.len) + { ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data, CRLF "--%0muA" CRLF "Content-Type: %V; charset=%V" CRLF @@ -461,8 +465,6 @@ ngx_http_range_multipart_header(ngx_http_request_t *r, &r->headers_out.charset) - ctx->boundary_header.data; - r->headers_out.charset.len = 0; - } else if (r->headers_out.content_type.len) { ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data, CRLF "--%0muA" CRLF @@ -501,6 +503,8 @@ ngx_http_range_multipart_header(ngx_http_request_t *r, r->headers_out.content_type_len = r->headers_out.content_type.len; + r->headers_out.charset.len = 0; + /* the size of the last boundary CRLF "--0123456789--" CRLF */ len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN + sizeof("--" CRLF) - 1; diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c index 70f6ac1de..884cb500a 100644 --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -885,7 +885,7 @@ ngx_http_scgi_process_status_line(ngx_http_request_t *r) return ngx_http_scgi_process_header(r); } - if (u->state) { + if (u->state && u->state->status == 0) { u->state->status = status->code; } @@ -1013,7 +1013,7 @@ ngx_http_scgi_process_header(ngx_http_request_t *r) ngx_str_set(&u->headers_in.status_line, "200 OK"); } - if (u->state) { + if (u->state && u->state->status == 0) { u->state->status = u->headers_in.status_n; } diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index df1e55ee9..206f58d25 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -270,6 +270,9 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { { ngx_string("ssl_session_id"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_session_id, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_session_reused"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_session_reused, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_client_cert"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_certificate, NGX_HTTP_VAR_CHANGEABLE, 0 }, diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c index f55e606c8..17dfc3b3a 100644 --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -1017,7 +1017,7 @@ ngx_http_uwsgi_process_status_line(ngx_http_request_t *r) return ngx_http_uwsgi_process_header(r); } - if (u->state) { + if (u->state && u->state->status == 0) { u->state->status = status->code; } @@ -1145,7 +1145,7 @@ ngx_http_uwsgi_process_header(ngx_http_request_t *r) ngx_str_set(&u->headers_in.status_line, "200 OK"); } - if (u->state) { + if (u->state && u->state->status == 0) { u->state->status = u->headers_in.status_n; } diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 8abf864d5..74a448a88 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -2632,6 +2632,14 @@ ngx_http_named_location(ngx_http_request_t *r, ngx_str_t *name) return NGX_DONE; } + if (r->uri.len == 0) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "empty URI in redirect to named location \"%V\"", name); + + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_DONE; + } + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); if (cscf->named_locations) { diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 0bb1b8cde..5f2cf7d39 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -2707,7 +2707,7 @@ ngx_http_test_reading(ngx_http_request_t *r) if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len) == -1) { - err = ngx_errno; + err = ngx_socket_errno; } goto closed; diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c index 94cdbeed6..bbf16fd25 100644 --- a/src/http/ngx_http_request_body.c +++ b/src/http/ngx_http_request_body.c @@ -953,13 +953,13 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in) if (clcf->client_max_body_size && clcf->client_max_body_size - < r->headers_in.content_length_n + rb->chunked->size) + - r->headers_in.content_length_n < rb->chunked->size) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client intended to send too large chunked " - "body: %O bytes", - r->headers_in.content_length_n - + rb->chunked->size); + "body: %O+%O bytes", + r->headers_in.content_length_n, + rb->chunked->size); r->lingering_close = 1; diff --git a/src/http/ngx_http_spdy.c b/src/http/ngx_http_spdy.c index 20755f490..4005bfbe7 100644 --- a/src/http/ngx_http_spdy.c +++ b/src/http/ngx_http_spdy.c @@ -1038,7 +1038,7 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos, "spdy HEADERS block consists of %ui entries", sc->entries); - if (ngx_list_init(&r->headers_in.headers, r->pool, sc->entries + 3, + if (ngx_list_init(&r->headers_in.headers, r->pool, 20, sizeof(ngx_table_elt_t)) != NGX_OK) { @@ -2325,7 +2325,7 @@ static ngx_int_t ngx_http_spdy_parse_header(ngx_http_request_t *r) { u_char *p, *end, ch; - ngx_uint_t len, hash; + ngx_uint_t hash; ngx_http_core_srv_conf_t *cscf; enum { @@ -2348,9 +2348,9 @@ ngx_http_spdy_parse_header(ngx_http_request_t *r) return NGX_AGAIN; } - len = ngx_spdy_frame_parse_uint32(p); + r->lowcase_index = ngx_spdy_frame_parse_uint32(p); - if (!len) { + if (r->lowcase_index == 0) { return NGX_HTTP_PARSE_INVALID_HEADER; } @@ -2359,8 +2359,6 @@ ngx_http_spdy_parse_header(ngx_http_request_t *r) p += NGX_SPDY_NV_NLEN_SIZE; - r->header_name_end = p + len; - r->lowcase_index = len; r->invalid_header = 0; state = sw_name; @@ -2369,16 +2367,16 @@ ngx_http_spdy_parse_header(ngx_http_request_t *r) case sw_name: - if (r->header_name_end > end) { + if ((ngx_uint_t) (end - p) < r->lowcase_index) { break; } cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); r->header_name_start = p; + r->header_name_end = p + r->lowcase_index; if (p[0] == ':') { - r->lowcase_index--; p++; } @@ -2425,29 +2423,26 @@ ngx_http_spdy_parse_header(ngx_http_request_t *r) break; } - len = ngx_spdy_frame_parse_uint32(p); + r->lowcase_index = ngx_spdy_frame_parse_uint32(p); /* null-terminate header name */ *p = '\0'; p += NGX_SPDY_NV_VLEN_SIZE; - r->header_end = p + len; - state = sw_value; /* fall through */ case sw_value: - if (r->header_end > end) { + if ((ngx_uint_t) (end - p) < r->lowcase_index) { break; } r->header_start = p; - for ( /* void */ ; p != r->header_end; p++) { - + while (r->lowcase_index--) { ch = *p; if (ch == '\0') { @@ -2456,7 +2451,7 @@ ngx_http_spdy_parse_header(ngx_http_request_t *r) return NGX_ERROR; } - r->header_size = p - r->header_start; + r->header_end = p; r->header_in->pos = p + 1; return NGX_OK; @@ -2465,9 +2460,11 @@ ngx_http_spdy_parse_header(ngx_http_request_t *r) if (ch == CR || ch == LF) { return NGX_HTTP_PARSE_INVALID_HEADER; } + + p++; } - r->header_size = p - r->header_start; + r->header_end = p; r->header_in->pos = p; r->state = 0; @@ -2526,13 +2523,6 @@ ngx_http_spdy_alloc_large_header_buffer(ngx_http_request_t *r) buf->last = ngx_cpymem(new, old, rest); } - if (r->header_name_end > old) { - r->header_name_end = new + (r->header_name_end - old); - - } else if (r->header_end > old) { - r->header_end = new + (r->header_end - old); - } - r->header_in = buf; stream->header_buffers++; @@ -2563,14 +2553,14 @@ ngx_http_spdy_handle_request_header(ngx_http_request_t *r) } if (r->header_name_start[0] == ':') { + r->header_name_start++; + for (i = 0; i < NGX_SPDY_REQUEST_HEADERS; i++) { sh = &ngx_http_spdy_request_headers[i]; if (sh->hash != r->header_hash - || sh->len != r->lowcase_index - || ngx_strncmp(sh->header, &r->header_name_start[1], - r->lowcase_index) - != 0) + || sh->len != r->header_name_end - r->header_name_start + || ngx_strncmp(sh->header, r->header_name_start, sh->len) != 0) { continue; } @@ -2590,10 +2580,10 @@ ngx_http_spdy_handle_request_header(ngx_http_request_t *r) h->hash = r->header_hash; - h->key.len = r->lowcase_index; + h->key.len = r->header_name_end - r->header_name_start; h->key.data = r->header_name_start; - h->value.len = r->header_size; + h->value.len = r->header_end - r->header_start; h->value.data = r->header_start; h->lowcase_key = h->key.data; @@ -2653,7 +2643,7 @@ ngx_http_spdy_parse_method(ngx_http_request_t *r) return NGX_HTTP_PARSE_INVALID_HEADER; } - len = r->header_size; + len = r->header_end - r->header_start; r->method_name.len = len; r->method_name.data = r->header_start; @@ -2733,10 +2723,10 @@ ngx_http_spdy_parse_host(ngx_http_request_t *r) h->hash = r->header_hash; - h->key.len = r->lowcase_index; - h->key.data = &r->header_name_start[1]; + h->key.len = r->header_name_end - r->header_name_start; + h->key.data = r->header_name_start; - h->value.len = r->header_size; + h->value.len = r->header_end - r->header_start; h->value.data = r->header_start; h->lowcase_key = h->key.data; @@ -2778,7 +2768,7 @@ ngx_http_spdy_parse_version(ngx_http_request_t *r) p = r->header_start; - if (r->header_size < 8 || !(ngx_str5cmp(p, 'H', 'T', 'T', 'P', '/'))) { + if (r->header_end - p < 8 || !(ngx_str5cmp(p, 'H', 'T', 'T', 'P', '/'))) { return NGX_HTTP_PARSE_INVALID_REQUEST; } @@ -2794,6 +2784,10 @@ ngx_http_spdy_parse_version(ngx_http_request_t *r) ch = *p; + if (ch == '.') { + break; + } + if (ch < '0' || ch > '9') { return NGX_HTTP_PARSE_INVALID_REQUEST; } @@ -2824,7 +2818,7 @@ ngx_http_spdy_parse_version(ngx_http_request_t *r) r->http_minor = r->http_minor * 10 + ch - '0'; } - r->http_protocol.len = r->header_size; + r->http_protocol.len = r->header_end - r->header_start; r->http_protocol.data = r->header_start; r->http_version = r->http_major * 1000 + r->http_minor; diff --git a/src/http/ngx_http_spdy.h b/src/http/ngx_http_spdy.h index b98b4d85a..55aceda89 100644 --- a/src/http/ngx_http_spdy.h +++ b/src/http/ngx_http_spdy.h @@ -174,6 +174,9 @@ ngx_http_spdy_queue_frame(ngx_http_spdy_connection_t *sc, for (out = &sc->last_out; *out; out = &(*out)->next) { + /* + * NB: higher values represent lower priorities. + */ if (frame->priority >= (*out)->priority) { break; } diff --git a/src/http/ngx_http_spdy_filter_module.c b/src/http/ngx_http_spdy_filter_module.c index 8a3f0a3c8..92c760243 100644 --- a/src/http/ngx_http_spdy_filter_module.c +++ b/src/http/ngx_http_spdy_filter_module.c @@ -967,7 +967,10 @@ ngx_http_spdy_waiting_queue(ngx_http_spdy_connection_t *sc, { s = ngx_queue_data(q, ngx_http_spdy_stream_t, queue); - if (s->priority >= stream->priority) { + /* + * NB: higher values represent lower priorities. + */ + if (stream->priority >= s->priority) { break; } } diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 26b576441..cf9ca0d5c 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -715,7 +715,7 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u) if (r->cache->header_start + 256 >= u->conf->buffer_size) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%V_buffer_size %uz is not enough for cache key, " - "it should increased at least to %uz", + "it should be increased to at least %uz", &u->conf->module, u->conf->buffer_size, ngx_align(r->cache->header_start + 256, 1024)); @@ -1096,7 +1096,7 @@ ngx_http_upstream_check_broken_connection(ngx_http_request_t *r, if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len) == -1) { - err = ngx_errno; + err = ngx_socket_errno; } if (err) { @@ -1977,7 +1977,7 @@ ngx_http_upstream_test_connect(ngx_connection_t *c) if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len) == -1) { - err = ngx_errno; + err = ngx_socket_errno; } if (err) { @@ -2557,7 +2557,9 @@ ngx_http_upstream_upgrade(ngx_http_request_t *r, ngx_http_upstream_t *u) if (u->peer.connection->read->ready || u->buffer.pos != u->buffer.last) { + ngx_post_event(c->read, &ngx_posted_events); ngx_http_upstream_process_upgraded(r, 1, 1); + return; } ngx_http_upstream_process_upgraded(r, 0, 1); diff --git a/src/os/unix/ngx_freebsd_sendfile_chain.c b/src/os/unix/ngx_freebsd_sendfile_chain.c index b8665e042..11cec8226 100644 --- a/src/os/unix/ngx_freebsd_sendfile_chain.c +++ b/src/os/unix/ngx_freebsd_sendfile_chain.c @@ -231,7 +231,7 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) && c->tcp_nopush == NGX_TCP_NOPUSH_UNSET) { if (ngx_tcp_nopush(c->fd) == NGX_ERROR) { - err = ngx_errno; + err = ngx_socket_errno; /* * there is a tiny chance to be interrupted, however, diff --git a/src/os/unix/ngx_linux_sendfile_chain.c b/src/os/unix/ngx_linux_sendfile_chain.c index 431542d42..16395f943 100644 --- a/src/os/unix/ngx_linux_sendfile_chain.c +++ b/src/os/unix/ngx_linux_sendfile_chain.c @@ -163,7 +163,7 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, (const void *) &tcp_nodelay, sizeof(int)) == -1) { - err = ngx_errno; + err = ngx_socket_errno; /* * there is a tiny chance to be interrupted, however, @@ -189,7 +189,7 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) if (c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) { if (ngx_tcp_nopush(c->fd) == NGX_ERROR) { - err = ngx_errno; + err = ngx_socket_errno; /* * there is a tiny chance to be interrupted, however, |