Merge branch 'nginx' (nginx-1.21.1).
Change-Id: Idf23a3d2ebd74b7468481f80e1222a5e18cbcd4c
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
diff --git a/.hgtags b/.hgtags
index ea345c9..ecf429e 100644
--- a/.hgtags
+++ b/.hgtags
@@ -461,3 +461,4 @@
da571b8eaf8f30f36c43b3c9b25e01e31f47149c release-1.19.9
ffcbb9980ee2bad27b4d7b1cd680b14ff47b29aa release-1.19.10
df34dcc9ac072ffd0945e5a1f3eb7987e8275375 release-1.21.0
+a68ac0677f8553b1f84d357bc9da114731ab5f47 release-1.21.1
diff --git a/contrib/vim/syntax/nginx.vim b/contrib/vim/syntax/nginx.vim
index 88ec847..4907e2a 100644
--- a/contrib/vim/syntax/nginx.vim
+++ b/contrib/vim/syntax/nginx.vim
@@ -152,6 +152,7 @@
syn keyword ngxDirective contained auth_jwt_key_file
syn keyword ngxDirective contained auth_jwt_key_request
syn keyword ngxDirective contained auth_jwt_leeway
+syn keyword ngxDirective contained auth_jwt_type
syn keyword ngxDirective contained auth_request
syn keyword ngxDirective contained auth_request_set
syn keyword ngxDirective contained autoindex
@@ -332,16 +333,20 @@
syn keyword ngxDirective contained iocp_threads
syn keyword ngxDirective contained ip_hash
syn keyword ngxDirective contained js_access
+syn keyword ngxDirective contained js_body_filter
syn keyword ngxDirective contained js_content
syn keyword ngxDirective contained js_filter
+syn keyword ngxDirective contained js_header_filter
syn keyword ngxDirective contained js_import
syn keyword ngxDirective contained js_include
syn keyword ngxDirective contained js_path
syn keyword ngxDirective contained js_preread
syn keyword ngxDirective contained js_set
+syn keyword ngxDirective contained js_var
syn keyword ngxDirective contained keepalive
syn keyword ngxDirective contained keepalive_disable
syn keyword ngxDirective contained keepalive_requests
+syn keyword ngxDirective contained keepalive_time
syn keyword ngxDirective contained keepalive_timeout
syn keyword ngxDirective contained keyval
syn keyword ngxDirective contained keyval_zone
@@ -373,6 +378,7 @@
syn keyword ngxDirective contained map_hash_bucket_size
syn keyword ngxDirective contained map_hash_max_size
syn keyword ngxDirective contained master_process
+syn keyword ngxDirective contained max_errors
syn keyword ngxDirective contained max_ranges
syn keyword ngxDirective contained memcached_bind
syn keyword ngxDirective contained memcached_buffer_size
@@ -1080,6 +1086,8 @@
syn keyword ngxDirectiveThirdParty contained nchan_subscribe_request
syn keyword ngxDirectiveThirdParty contained nchan_subscriber_first_message
syn keyword ngxDirectiveThirdParty contained nchan_subscriber_http_raw_stream_separator
+syn keyword ngxDirectiveThirdParty contained nchan_subscriber_info
+syn keyword ngxDirectiveThirdParty contained nchan_subscriber_info_string
syn keyword ngxDirectiveThirdParty contained nchan_subscriber_last_message_id
syn keyword ngxDirectiveThirdParty contained nchan_subscriber_location
syn keyword ngxDirectiveThirdParty contained nchan_subscriber_message_id_custom_etag_header
@@ -2368,9 +2376,9 @@
" IP2Location Nginx
" https://github.com/ip2location/ip2location-nginx
-syn keyword ngxDirectiveThirdParty contained ip2location_proxy
-syn keyword ngxDirectiveThirdParty contained ip2location_proxy_recursive
+syn keyword ngxDirectiveThirdParty contained ip2location_addresstype
syn keyword ngxDirectiveThirdParty contained ip2location_areacode
+syn keyword ngxDirectiveThirdParty contained ip2location_category
syn keyword ngxDirectiveThirdParty contained ip2location_city
syn keyword ngxDirectiveThirdParty contained ip2location_country_long
syn keyword ngxDirectiveThirdParty contained ip2location_country_short
@@ -2384,6 +2392,8 @@
syn keyword ngxDirectiveThirdParty contained ip2location_mnc
syn keyword ngxDirectiveThirdParty contained ip2location_mobilebrand
syn keyword ngxDirectiveThirdParty contained ip2location_netspeed
+syn keyword ngxDirectiveThirdParty contained ip2location_proxy
+syn keyword ngxDirectiveThirdParty contained ip2location_proxy_recursive
syn keyword ngxDirectiveThirdParty contained ip2location_region
syn keyword ngxDirectiveThirdParty contained ip2location_timezone
syn keyword ngxDirectiveThirdParty contained ip2location_usagetype
@@ -2403,6 +2413,7 @@
syn keyword ngxDirectiveThirdParty contained ip2proxy_isp
syn keyword ngxDirectiveThirdParty contained ip2proxy_is_proxy
syn keyword ngxDirectiveThirdParty contained ip2proxy_last_seen
+syn keyword ngxDirectiveThirdParty contained ip2proxy_provider
syn keyword ngxDirectiveThirdParty contained ip2proxy_proxy
syn keyword ngxDirectiveThirdParty contained ip2proxy_proxy_recursive
syn keyword ngxDirectiveThirdParty contained ip2proxy_proxy_type
diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml
index ea3551a..1fb7634 100644
--- a/docs/xml/nginx/changes.xml
+++ b/docs/xml/nginx/changes.xml
@@ -5,6 +5,125 @@
<change_log title="nginx">
+<changes ver="1.21.1" date="2021-07-06">
+
+<change type="change">
+<para lang="ru">
+теперь nginx для метода CONNECT всегда возвращает ошибку.
+</para>
+<para lang="en">
+now nginx always returns an error for the CONNECT method.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+теперь nginx всегда возвращает ошибку,
+если в запросе одновременно присутствуют строки заголовка "Content-Length"
+и "Transfer-Encoding".
+</para>
+<para lang="en">
+now nginx always returns an error
+if both "Content-Length" and "Transfer-Encoding" header lines
+are present in the request.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+теперь nginx всегда возвращает ошибку,
+если в строке запроса используются пробелы или управляющие символы.
+</para>
+<para lang="en">
+now nginx always returns an error
+if spaces or control characters are used in the request line.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+теперь nginx всегда возвращает ошибку,
+если в имени заголовка используются пробелы или управляющие символы.
+</para>
+<para lang="en">
+now nginx always returns an error
+if spaces or control characters are used in a header name.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+теперь nginx всегда возвращает ошибку,
+если в строке "Host" заголовка запроса
+используются пробелы или управляющие символы.
+</para>
+<para lang="en">
+now nginx always returns an error
+if spaces or control characters
+are used in the "Host" request header line.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+оптимизация тестирования конфигурации
+при использовании большого количества listen-сокетов.
+</para>
+<para lang="en">
+optimization of configuration testing
+when using many listening sockets.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+nginx не экранировал
+символы """, "<", ">", "\", "^", "`", "{", "|", и "}"
+при проксировании с изменением URI запроса.
+</para>
+<para lang="en">
+nginx did not escape
+""", "<", ">", "\", "^", "`", "{", "|", and "}" characters
+when proxying with changed URI.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+SSL-переменные могли быть пустыми при записи в лог;
+ошибка появилась в 1.19.5.
+</para>
+<para lang="en">
+SSL variables might be empty when used in logs;
+the bug had appeared in 1.19.5.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+keepalive-соединения с gRPC-бэкендами могли не закрываться
+после получения GOAWAY-фрейма.
+</para>
+<para lang="en">
+keepalive connections with gRPC backends might not be closed
+after receiving a GOAWAY frame.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+уменьшено потребление памяти для долгоживущих запросов
+при проксировании с использованием более 64 буферов.
+</para>
+<para lang="en">
+reduced memory consumption for long-lived requests
+when proxying with more than 64 buffers.
+</para>
+</change>
+
+</changes>
+
+
<changes ver="1.21.0" date="2021-05-25">
<change type="security">
diff --git a/src/core/nginx.h b/src/core/nginx.h
index be3ee7c..a7a34de 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -13,8 +13,8 @@
#define NGINX_NAME "nginx"
#endif
-#define nginx_version 1021000
-#define NGINX_VERSION "1.21.0"
+#define nginx_version 1021001
+#define NGINX_VERSION "1.21.1"
#define NGINX_VER NGINX_NAME "/" NGINX_VERSION
#ifdef NGX_BUILD
diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c
index 8339e2b..fe729a7 100644
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -495,21 +495,24 @@
return NGX_ERROR;
}
- if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
- (const void *) &reuseaddr, sizeof(int))
- == -1)
- {
- ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
- "setsockopt(SO_REUSEADDR) %V failed",
- &ls[i].addr_text);
+ if (ls[i].type != SOCK_DGRAM || !ngx_test_config) {
- if (ngx_close_socket(s) == -1) {
+ if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+ (const void *) &reuseaddr, sizeof(int))
+ == -1)
+ {
ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
- ngx_close_socket_n " %V failed",
+ "setsockopt(SO_REUSEADDR) %V failed",
&ls[i].addr_text);
- }
- return NGX_ERROR;
+ if (ngx_close_socket(s) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+ ngx_close_socket_n " %V failed",
+ &ls[i].addr_text);
+ }
+
+ return NGX_ERROR;
+ }
}
#if (NGX_HAVE_REUSEPORT)
diff --git a/src/core/ngx_rbtree.h b/src/core/ngx_rbtree.h
index 97f0e3e..e8c3582 100644
--- a/src/core/ngx_rbtree.h
+++ b/src/core/ngx_rbtree.h
@@ -47,6 +47,9 @@
(tree)->sentinel = s; \
(tree)->insert = i
+#define ngx_rbtree_data(node, type, link) \
+ (type *) ((u_char *) (node) - offsetof(type, link))
+
void ngx_rbtree_insert(ngx_rbtree_t *tree, ngx_rbtree_node_t *node);
void ngx_rbtree_delete(ngx_rbtree_t *tree, ngx_rbtree_node_t *node);
diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c
index 58d5f3e..6d129e5 100644
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -51,9 +51,7 @@
} ngx_resolver_an_t;
-#define ngx_resolver_node(n) \
- (ngx_resolver_node_t *) \
- ((u_char *) (n) - offsetof(ngx_resolver_node_t, node))
+#define ngx_resolver_node(n) ngx_rbtree_data(n, ngx_resolver_node_t, node)
static ngx_int_t ngx_udp_connect(ngx_resolver_connection_t *rec);
diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c
index 5cc9b26..98f270a 100644
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -1493,19 +1493,32 @@
uint32_t *escape;
static u_char hex[] = "0123456789ABCDEF";
- /* " ", "#", "%", "?", %00-%1F, %7F-%FF */
+ /*
+ * Per RFC 3986 only the following chars are allowed in URIs unescaped:
+ *
+ * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ * gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
+ * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
+ * / "*" / "+" / "," / ";" / "="
+ *
+ * And "%" can appear as a part of escaping itself. The following
+ * characters are not allowed and need to be escaped: %00-%1F, %7F-%FF,
+ * " ", """, "<", ">", "\", "^", "`", "{", "|", "}".
+ */
+
+ /* " ", "#", "%", "?", not allowed */
static uint32_t uri[] = {
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
/* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
- 0x80000029, /* 1000 0000 0000 0000 0000 0000 0010 1001 */
+ 0xd000002d, /* 1101 0000 0000 0000 0000 0000 0010 1101 */
/* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
- 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
+ 0x50000000, /* 0101 0000 0000 0000 0000 0000 0000 0000 */
/* ~}| {zyx wvut srqp onml kjih gfed cba` */
- 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
+ 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
@@ -1513,19 +1526,19 @@
0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
};
- /* " ", "#", "%", "&", "+", "?", %00-%1F, %7F-%FF */
+ /* " ", "#", "%", "&", "+", ";", "?", not allowed */
static uint32_t args[] = {
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
/* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
- 0x88000869, /* 1000 1000 0000 0000 0000 1000 0110 1001 */
+ 0xd800086d, /* 1101 1000 0000 0000 0000 1000 0110 1101 */
/* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
- 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
+ 0x50000000, /* 0101 0000 0000 0000 0000 0000 0000 0000 */
/* ~}| {zyx wvut srqp onml kjih gfed cba` */
- 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
+ 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
@@ -1553,19 +1566,19 @@
0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
};
- /* " ", "#", """, "%", "'", %00-%1F, %7F-%FF */
+ /* " ", "#", """, "%", "'", not allowed */
static uint32_t html[] = {
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
/* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
- 0x000000ad, /* 0000 0000 0000 0000 0000 0000 1010 1101 */
+ 0x500000ad, /* 0101 0000 0000 0000 0000 0000 1010 1101 */
/* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
- 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
+ 0x50000000, /* 0101 0000 0000 0000 0000 0000 0000 0000 */
/* ~}| {zyx wvut srqp onml kjih gfed cba` */
- 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
+ 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
@@ -1573,19 +1586,19 @@
0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
};
- /* " ", """, "'", %00-%1F, %7F-%FF */
+ /* " ", """, "'", not allowed */
static uint32_t refresh[] = {
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
/* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
- 0x00000085, /* 0000 0000 0000 0000 0000 0000 1000 0101 */
+ 0x50000085, /* 0101 0000 0000 0000 0000 0000 1000 0101 */
/* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
- 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
+ 0x50000000, /* 0101 0000 0000 0000 0000 0000 0000 0000 */
/* ~}| {zyx wvut srqp onml kjih gfed cba` */
- 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
+ 0xd8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c
index 49dca57..f0d3891 100644
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -441,20 +441,23 @@
#if (NGX_HAVE_REUSEPORT)
- ls = cycle->listening.elts;
- for (i = 0; i < cycle->listening.nelts; i++) {
-
- if (!ls[i].reuseport || ls[i].worker != 0) {
- continue;
- }
-
- if (ngx_clone_listening(cycle, &ls[i]) != NGX_OK) {
- return NGX_CONF_ERROR;
- }
-
- /* cloning may change cycle->listening.elts */
+ if (!ngx_test_config) {
ls = cycle->listening.elts;
+ for (i = 0; i < cycle->listening.nelts; i++) {
+
+ if (!ls[i].reuseport || ls[i].worker != 0) {
+ continue;
+ }
+
+ if (ngx_clone_listening(cycle, &ls[i]) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ /* cloning may change cycle->listening.elts */
+
+ ls = cycle->listening.elts;
+ }
}
#endif
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index 69ec660..72b0da4 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -2919,9 +2919,12 @@
ngx_ssl_shutdown(ngx_connection_t *c)
{
int n, sslerr, mode;
+ ngx_int_t rc;
ngx_err_t err;
ngx_uint_t tries;
+ rc = NGX_OK;
+
ngx_ssl_ocsp_cleanup(c);
if (SSL_in_init(c->ssl->connection)) {
@@ -2931,11 +2934,7 @@
* Avoid calling SSL_shutdown() if handshake wasn't completed.
*/
- SSL_free(c->ssl->connection);
- c->ssl = NULL;
- c->recv = ngx_recv;
-
- return NGX_OK;
+ goto done;
}
if (c->timedout || c->error || c->buffered) {
@@ -2977,11 +2976,7 @@
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n);
if (n == 1) {
- SSL_free(c->ssl->connection);
- c->ssl = NULL;
- c->recv = ngx_recv;
-
- return NGX_OK;
+ goto done;
}
if (n == 0 && tries-- > 1) {
@@ -3007,11 +3002,11 @@
}
if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
- return NGX_ERROR;
+ goto failed;
}
if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
- return NGX_ERROR;
+ goto failed;
}
ngx_add_timer(c->read, 3000);
@@ -3020,23 +3015,33 @@
}
if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) {
- SSL_free(c->ssl->connection);
- c->ssl = NULL;
- c->recv = ngx_recv;
-
- return NGX_OK;
+ goto done;
}
err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0;
ngx_ssl_connection_error(c, sslerr, err, "SSL_shutdown() failed");
- SSL_free(c->ssl->connection);
- c->ssl = NULL;
- c->recv = ngx_recv;
-
- return NGX_ERROR;
+ break;
}
+
+failed:
+
+ rc = NGX_ERROR;
+
+done:
+
+ if (c->ssl->shutdown_without_free) {
+ c->ssl->shutdown_without_free = 0;
+ c->recv = ngx_recv;
+ return rc;
+ }
+
+ SSL_free(c->ssl->connection);
+ c->ssl = NULL;
+ c->recv = ngx_recv;
+
+ return rc;
}
diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h
index 49888d5..7d14647 100644
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -100,6 +100,7 @@
unsigned buffer:1;
unsigned no_wait_shutdown:1;
unsigned no_send_shutdown:1;
+ unsigned shutdown_without_free:1;
unsigned handshake_buffer_set:1;
unsigned try_early_data:1;
unsigned in_early:1;
diff --git a/src/event/ngx_event_timer.c b/src/event/ngx_event_timer.c
index 698b88f..35052bc 100644
--- a/src/event/ngx_event_timer.c
+++ b/src/event/ngx_event_timer.c
@@ -73,7 +73,7 @@
return;
}
- ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer));
+ ev = ngx_rbtree_data(node, ngx_event_t, timer);
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
"event timer del: %d: %M",
@@ -113,7 +113,7 @@
node;
node = ngx_rbtree_next(&ngx_event_timer_rbtree, node))
{
- ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer));
+ ev = ngx_rbtree_data(node, ngx_event_t, timer);
if (!ev->cancelable) {
return NGX_AGAIN;
diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c
index 5191880..69ac0f7 100644
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -2019,10 +2019,12 @@
break;
}
- /* there was error while a header line parsing */
+ /* rc == NGX_HTTP_PARSE_INVALID_HEADER */
- ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
- "upstream sent invalid header");
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "upstream sent invalid header: \"%*s\\x%02xd...\"",
+ r->header_end - r->header_name_start,
+ r->header_name_start, *r->header_end);
return NGX_HTTP_UPSTREAM_INVALID_HEADER;
}
diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c
index 2e20e5f..65bd1e6 100644
--- a/src/http/modules/ngx_http_grpc_module.c
+++ b/src/http/modules/ngx_http_grpc_module.c
@@ -121,6 +121,7 @@
unsigned done:1;
unsigned status:1;
unsigned rst:1;
+ unsigned goaway:1;
ngx_http_request_t *request;
@@ -1210,6 +1211,7 @@
ctx->done = 0;
ctx->status = 0;
ctx->rst = 0;
+ ctx->goaway = 0;
ctx->connection = NULL;
return NGX_OK;
@@ -1565,6 +1567,7 @@
&& ctx->out == NULL
&& ctx->output_closed
&& !ctx->output_blocked
+ && !ctx->goaway
&& ctx->state == ngx_http_grpc_st_start)
{
u->keepalive = 1;
@@ -1714,6 +1717,8 @@
return NGX_HTTP_UPSTREAM_INVALID_HEADER;
}
+ ctx->goaway = 1;
+
continue;
}
@@ -1907,6 +1912,7 @@
&& ctx->out == NULL
&& ctx->output_closed
&& !ctx->output_blocked
+ && !ctx->goaway
&& b->last == b->pos)
{
u->keepalive = 1;
@@ -2035,6 +2041,7 @@
if (ctx->in == NULL
&& ctx->output_closed
&& !ctx->output_blocked
+ && !ctx->goaway
&& ctx->state == ngx_http_grpc_st_start)
{
u->keepalive = 1;
@@ -2170,6 +2177,8 @@
}
ctx->rst = 1;
+
+ continue;
}
if (ctx->type == NGX_HTTP_V2_GOAWAY_FRAME) {
@@ -2204,6 +2213,8 @@
return NGX_ERROR;
}
+ ctx->goaway = 1;
+
continue;
}
@@ -3373,7 +3384,7 @@
return NGX_ERROR;
}
- if (ch == '\0' || ch == CR || ch == LF) {
+ if (ch <= 0x20 || ch == 0x7f) {
return NGX_ERROR;
}
}
@@ -3475,6 +3486,8 @@
return NGX_AGAIN;
}
+ ctx->state = ngx_http_grpc_st_start;
+
return NGX_OK;
}
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index ac21451..bcbb244 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -1193,7 +1193,7 @@
loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0;
- if (r->quoted_uri || r->space_in_uri || r->internal) {
+ if (r->quoted_uri || r->internal) {
escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
r->uri.len - loc_len, NGX_ESCAPE_URI);
} else {
@@ -1306,7 +1306,7 @@
loc_len = (r->valid_location && ctx->vars.uri.len) ?
plcf->location.len : 0;
- if (r->quoted_uri || r->space_in_uri || r->internal) {
+ if (r->quoted_uri || r->internal) {
escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
r->uri.len - loc_len, NGX_ESCAPE_URI);
}
@@ -2026,10 +2026,12 @@
return NGX_AGAIN;
}
- /* there was error while a header line parsing */
+ /* rc == NGX_HTTP_PARSE_INVALID_HEADER */
- ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
- "upstream sent invalid header");
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "upstream sent invalid header: \"%*s\\x%02xd...\"",
+ r->header_end - r->header_name_start,
+ r->header_name_start, *r->header_end);
return NGX_HTTP_UPSTREAM_INVALID_HEADER;
}
diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c
index 600999c..570713d 100644
--- a/src/http/modules/ngx_http_scgi_module.c
+++ b/src/http/modules/ngx_http_scgi_module.c
@@ -1140,10 +1140,12 @@
return NGX_AGAIN;
}
- /* there was error while a header line parsing */
+ /* rc == NGX_HTTP_PARSE_INVALID_HEADER */
- ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
- "upstream sent invalid header");
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "upstream sent invalid header: \"%*s\\x%02xd...\"",
+ r->header_end - r->header_name_start,
+ r->header_name_start, *r->header_end);
return NGX_HTTP_UPSTREAM_INVALID_HEADER;
}
diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c
index 655be98..40a06c7 100644
--- a/src/http/modules/ngx_http_uwsgi_module.c
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -1361,10 +1361,12 @@
return NGX_AGAIN;
}
- /* there was error while a header line parsing */
+ /* rc == NGX_HTTP_PARSE_INVALID_HEADER */
- ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
- "upstream sent invalid header");
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "upstream sent invalid header: \"%*s\\x%02xd...\"",
+ r->header_end - r->header_name_start,
+ r->header_name_start, *r->header_end);
return NGX_HTTP_UPSTREAM_INVALID_HEADER;
}
diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c
index 20ad89a..6460da2 100644
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -11,7 +11,7 @@
static uint32_t usual[] = {
- 0xffffdbfe, /* 1111 1111 1111 1111 1101 1011 1111 1110 */
+ 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
/* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
0x7fff37d6, /* 0111 1111 1111 1111 0011 0111 1101 0110 */
@@ -24,7 +24,7 @@
#endif
/* ~}| {zyx wvut srqp onml kjih gfed cba` */
- 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+ 0x7fffffff, /* 0111 1111 1111 1111 1111 1111 1111 1111 */
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
@@ -116,10 +116,8 @@
sw_host_end,
sw_host_ip_literal,
sw_port,
- sw_host_http_09,
sw_after_slash_in_uri,
sw_check_uri,
- sw_check_uri_http_09,
sw_uri,
sw_http_09,
sw_http_H,
@@ -246,6 +244,11 @@
r->method = NGX_HTTP_OPTIONS;
}
+ if (ngx_str7_cmp(m, 'C', 'O', 'N', 'N', 'E', 'C', 'T', ' '))
+ {
+ r->method = NGX_HTTP_CONNECT;
+ }
+
break;
case 8:
@@ -393,7 +396,7 @@
*/
r->uri_start = r->schema_end + 1;
r->uri_end = r->schema_end + 2;
- state = sw_host_http_09;
+ state = sw_http_09;
break;
default:
return NGX_HTTP_PARSE_INVALID_REQUEST;
@@ -467,35 +470,13 @@
*/
r->uri_start = r->schema_end + 1;
r->uri_end = r->schema_end + 2;
- state = sw_host_http_09;
+ state = sw_http_09;
break;
default:
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
break;
- /* space+ after "http://host[:port] " */
- case sw_host_http_09:
- switch (ch) {
- case ' ':
- break;
- case CR:
- r->http_minor = 9;
- state = sw_almost_done;
- break;
- case LF:
- r->http_minor = 9;
- goto done;
- case 'H':
- r->http_protocol.data = p;
- state = sw_http_H;
- break;
- default:
- return NGX_HTTP_PARSE_INVALID_REQUEST;
- }
- break;
-
-
/* check "/.", "//", "%", and "\" (Win32) in URI */
case sw_after_slash_in_uri:
@@ -507,7 +488,7 @@
switch (ch) {
case ' ':
r->uri_end = p;
- state = sw_check_uri_http_09;
+ state = sw_http_09;
break;
case CR:
r->uri_end = p;
@@ -547,9 +528,10 @@
case '+':
r->plus_in_uri = 1;
break;
- case '\0':
- return NGX_HTTP_PARSE_INVALID_REQUEST;
default:
+ if (ch < 0x20 || ch == 0x7f) {
+ return NGX_HTTP_PARSE_INVALID_REQUEST;
+ }
state = sw_check_uri;
break;
}
@@ -579,7 +561,7 @@
break;
case ' ':
r->uri_end = p;
- state = sw_check_uri_http_09;
+ state = sw_http_09;
break;
case CR:
r->uri_end = p;
@@ -611,36 +593,14 @@
case '+':
r->plus_in_uri = 1;
break;
- case '\0':
- return NGX_HTTP_PARSE_INVALID_REQUEST;
- }
- break;
-
- /* space+ after URI */
- case sw_check_uri_http_09:
- switch (ch) {
- case ' ':
- break;
- case CR:
- r->http_minor = 9;
- state = sw_almost_done;
- break;
- case LF:
- r->http_minor = 9;
- goto done;
- case 'H':
- r->http_protocol.data = p;
- state = sw_http_H;
- break;
default:
- r->space_in_uri = 1;
- state = sw_check_uri;
- p--;
+ if (ch < 0x20 || ch == 0x7f) {
+ return NGX_HTTP_PARSE_INVALID_REQUEST;
+ }
break;
}
break;
-
/* URI */
case sw_uri:
@@ -665,8 +625,11 @@
case '#':
r->complex_uri = 1;
break;
- case '\0':
- return NGX_HTTP_PARSE_INVALID_REQUEST;
+ default:
+ if (ch < 0x20 || ch == 0x7f) {
+ return NGX_HTTP_PARSE_INVALID_REQUEST;
+ }
+ break;
}
break;
@@ -687,10 +650,7 @@
state = sw_http_H;
break;
default:
- r->space_in_uri = 1;
- state = sw_uri;
- p--;
- break;
+ return NGX_HTTP_PARSE_INVALID_REQUEST;
}
break;
@@ -933,7 +893,8 @@
break;
}
- if (ch == '\0') {
+ if (ch <= 0x20 || ch == 0x7f || ch == ':') {
+ r->header_end = p;
return NGX_HTTP_PARSE_INVALID_HEADER;
}
@@ -1001,7 +962,8 @@
break;
}
- if (ch == '\0') {
+ if (ch <= 0x20 || ch == 0x7f) {
+ r->header_end = p;
return NGX_HTTP_PARSE_INVALID_HEADER;
}
@@ -1024,6 +986,7 @@
r->header_end = p;
goto done;
case '\0':
+ r->header_end = p;
return NGX_HTTP_PARSE_INVALID_HEADER;
default:
r->header_start = p;
@@ -1047,6 +1010,7 @@
r->header_end = p;
goto done;
case '\0':
+ r->header_end = p;
return NGX_HTTP_PARSE_INVALID_HEADER;
}
break;
@@ -1062,6 +1026,7 @@
case LF:
goto done;
case '\0':
+ r->header_end = p;
return NGX_HTTP_PARSE_INVALID_HEADER;
default:
state = sw_value;
@@ -1165,10 +1130,6 @@
}
switch (ch) {
- case ' ':
- r->space_in_uri = 1;
- state = sw_check_uri;
- break;
case '.':
r->complex_uri = 1;
state = sw_uri;
@@ -1199,6 +1160,9 @@
r->plus_in_uri = 1;
break;
default:
+ if (ch <= 0x20 || ch == 0x7f) {
+ return NGX_ERROR;
+ }
state = sw_check_uri;
break;
}
@@ -1226,9 +1190,6 @@
case '.':
r->uri_ext = p + 1;
break;
- case ' ':
- r->space_in_uri = 1;
- break;
#if (NGX_WIN32)
case '\\':
r->complex_uri = 1;
@@ -1250,6 +1211,11 @@
case '+':
r->plus_in_uri = 1;
break;
+ default:
+ if (ch <= 0x20 || ch == 0x7f) {
+ return NGX_ERROR;
+ }
+ break;
}
break;
@@ -1261,12 +1227,14 @@
}
switch (ch) {
- case ' ':
- r->space_in_uri = 1;
- break;
case '#':
r->complex_uri = 1;
break;
+ default:
+ if (ch <= 0x20 || ch == 0x7f) {
+ return NGX_ERROR;
+ }
+ break;
}
break;
}
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index eae56c6..de1b96b 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -1428,7 +1428,7 @@
r->unparsed_uri.len = r->uri_end - r->uri_start;
r->unparsed_uri.data = r->uri_start;
- r->valid_unparsed_uri = (r->space_in_uri || r->empty_path_in_uri) ? 0 : 1;
+ r->valid_unparsed_uri = r->empty_path_in_uri ? 0 : 1;
if (r->uri_ext) {
if (r->args_start) {
@@ -1686,7 +1686,9 @@
/* rc == NGX_HTTP_PARSE_INVALID_HEADER */
ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "client sent invalid header line");
+ "client sent invalid header line: \"%*s\\x%02xd...\"",
+ r->header_end - r->header_name_start,
+ r->header_name_start, *r->header_end);
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
break;
@@ -2160,20 +2162,20 @@
}
}
- if (r->method == NGX_HTTP_TRACE) {
- ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
- "client sent TRACE method");
- ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED);
- return NGX_ERROR;
- }
-
if (r->headers_in.transfer_encoding) {
if (r->headers_in.transfer_encoding->value.len == 7
&& ngx_strncasecmp(r->headers_in.transfer_encoding->value.data,
(u_char *) "chunked", 7) == 0)
{
- r->headers_in.content_length = NULL;
- r->headers_in.content_length_n = -1;
+ if (r->headers_in.content_length) {
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent \"Content-Length\" and "
+ "\"Transfer-Encoding\" headers "
+ "at the same time");
+ ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
+ return NGX_ERROR;
+ }
+
r->headers_in.chunked = 1;
} else {
@@ -2193,6 +2195,20 @@
}
}
+ if (r->method == NGX_HTTP_CONNECT) {
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent CONNECT method");
+ ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED);
+ return NGX_ERROR;
+ }
+
+ if (r->method == NGX_HTTP_TRACE) {
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent TRACE method");
+ ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED);
+ return NGX_ERROR;
+ }
+
return NGX_OK;
}
@@ -2340,15 +2356,16 @@
}
break;
- case '\0':
- return NGX_DECLINED;
-
default:
if (ngx_path_separator(ch)) {
return NGX_DECLINED;
}
+ if (ch <= 0x20 || ch == 0x7f) {
+ return NGX_DECLINED;
+ }
+
if (ch >= 'A' && ch <= 'Z') {
alloc = 1;
}
@@ -3580,6 +3597,8 @@
if (c->ssl) {
ngx_int_t rc;
+ c->ssl->shutdown_without_free = 1;
+
rc = ngx_ssl_shutdown(c);
if (rc == NGX_ERROR) {
diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
index 68d5c18..4e0ca8a 100644
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -25,22 +25,23 @@
#define NGX_HTTP_VERSION_11 1001
#define NGX_HTTP_VERSION_20 2000
-#define NGX_HTTP_UNKNOWN 0x0001
-#define NGX_HTTP_GET 0x0002
-#define NGX_HTTP_HEAD 0x0004
-#define NGX_HTTP_POST 0x0008
-#define NGX_HTTP_PUT 0x0010
-#define NGX_HTTP_DELETE 0x0020
-#define NGX_HTTP_MKCOL 0x0040
-#define NGX_HTTP_COPY 0x0080
-#define NGX_HTTP_MOVE 0x0100
-#define NGX_HTTP_OPTIONS 0x0200
-#define NGX_HTTP_PROPFIND 0x0400
-#define NGX_HTTP_PROPPATCH 0x0800
-#define NGX_HTTP_LOCK 0x1000
-#define NGX_HTTP_UNLOCK 0x2000
-#define NGX_HTTP_PATCH 0x4000
-#define NGX_HTTP_TRACE 0x8000
+#define NGX_HTTP_UNKNOWN 0x00000001
+#define NGX_HTTP_GET 0x00000002
+#define NGX_HTTP_HEAD 0x00000004
+#define NGX_HTTP_POST 0x00000008
+#define NGX_HTTP_PUT 0x00000010
+#define NGX_HTTP_DELETE 0x00000020
+#define NGX_HTTP_MKCOL 0x00000040
+#define NGX_HTTP_COPY 0x00000080
+#define NGX_HTTP_MOVE 0x00000100
+#define NGX_HTTP_OPTIONS 0x00000200
+#define NGX_HTTP_PROPFIND 0x00000400
+#define NGX_HTTP_PROPPATCH 0x00000800
+#define NGX_HTTP_LOCK 0x00001000
+#define NGX_HTTP_UNLOCK 0x00002000
+#define NGX_HTTP_PATCH 0x00004000
+#define NGX_HTTP_TRACE 0x00008000
+#define NGX_HTTP_CONNECT 0x00010000
#define NGX_HTTP_CONNECTION_CLOSE 1
#define NGX_HTTP_CONNECTION_KEEP_ALIVE 2
@@ -467,9 +468,6 @@
/* URI with "+" */
unsigned plus_in_uri:1;
- /* URI with " " */
- unsigned space_in_uri:1;
-
/* URI with empty path */
unsigned empty_path_in_uri:1;
diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
index 8bf51da..82279eb 100644
--- a/src/http/v2/ngx_http_v2.c
+++ b/src/http/v2/ngx_http_v2.c
@@ -3500,7 +3500,7 @@
continue;
}
- if (ch == '\0' || ch == LF || ch == CR || ch == ':'
+ if (ch <= 0x20 || ch == 0x7f || ch == ':'
|| (ch >= 'A' && ch <= 'Z'))
{
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
@@ -3649,7 +3649,8 @@
{ 4, "LOCK", NGX_HTTP_LOCK },
{ 6, "UNLOCK", NGX_HTTP_UNLOCK },
{ 5, "PATCH", NGX_HTTP_PATCH },
- { 5, "TRACE", NGX_HTTP_TRACE }
+ { 5, "TRACE", NGX_HTTP_TRACE },
+ { 7, "CONNECT", NGX_HTTP_CONNECT }
}, *test;
if (r->method_name.len) {
diff --git a/src/os/unix/ngx_readv_chain.c b/src/os/unix/ngx_readv_chain.c
index a3577ce..b1ae4b5 100644
--- a/src/os/unix/ngx_readv_chain.c
+++ b/src/os/unix/ngx_readv_chain.c
@@ -96,7 +96,7 @@
iov->iov_len += n;
} else {
- if (vec.nelts >= IOV_MAX) {
+ if (vec.nelts == vec.nalloc) {
break;
}
diff --git a/src/os/win32/ngx_win32_init.c b/src/os/win32/ngx_win32_init.c
index 3249fb2..de66a44 100644
--- a/src/os/win32/ngx_win32_init.c
+++ b/src/os/win32/ngx_win32_init.c
@@ -295,7 +295,7 @@
osviex_stub = (ngx_osviex_stub_t *) &osvi.wServicePackMinor;
ngx_log_error(NGX_LOG_INFO, log, 0,
- "OS: %ud build:%ud, \"%s\", suite:%Xd, type:%ud",
+ "OS: %ui build:%ud, \"%s\", suite:%Xd, type:%ud",
ngx_win32_version, osvi.dwBuildNumber, osvi.szCSDVersion,
osviex_stub->wSuiteMask, osviex_stub->wProductType);
@@ -305,7 +305,7 @@
/* Win9x build */
ngx_log_error(NGX_LOG_INFO, log, 0,
- "OS: %u build:%ud.%ud.%ud, \"%s\"",
+ "OS: %ui build:%ud.%ud.%ud, \"%s\"",
ngx_win32_version,
osvi.dwBuildNumber >> 24,
(osvi.dwBuildNumber >> 16) & 0xff,
@@ -321,7 +321,7 @@
* and we do not support VER_PLATFORM_WIN32s at all
*/
- ngx_log_error(NGX_LOG_INFO, log, 0, "OS: %ud build:%ud, \"%s\"",
+ ngx_log_error(NGX_LOG_INFO, log, 0, "OS: %ui build:%ud, \"%s\"",
ngx_win32_version, osvi.dwBuildNumber,
osvi.szCSDVersion);
}
diff --git a/src/os/win32/ngx_wsarecv_chain.c b/src/os/win32/ngx_wsarecv_chain.c
index 87f0239..4f95d5a 100644
--- a/src/os/win32/ngx_wsarecv_chain.c
+++ b/src/os/win32/ngx_wsarecv_chain.c
@@ -10,7 +10,7 @@
#include <ngx_event.h>
-#define NGX_WSABUFS 8
+#define NGX_WSABUFS 64
ssize_t
@@ -57,6 +57,10 @@
wsabuf->len += n;
} else {
+ if (vec.nelts == vec.nalloc) {
+ break;
+ }
+
wsabuf = ngx_array_push(&vec);
if (wsabuf == NULL) {
return NGX_ERROR;
diff --git a/src/os/win32/ngx_wsasend_chain.c b/src/os/win32/ngx_wsasend_chain.c
index e2dde22..cd50e71 100644
--- a/src/os/win32/ngx_wsasend_chain.c
+++ b/src/os/win32/ngx_wsasend_chain.c
@@ -10,7 +10,7 @@
#include <ngx_event.h>
-#define NGX_WSABUFS 8
+#define NGX_WSABUFS 64
ngx_chain_t *
@@ -47,7 +47,7 @@
vec.elts = wsabufs;
vec.size = sizeof(WSABUF);
- vec.nalloc = NGX_WSABUFS;
+ vec.nalloc = ngx_min(NGX_WSABUFS, ngx_max_wsabufs);
vec.pool = c->pool;
for ( ;; ) {
@@ -59,10 +59,8 @@
/* create the WSABUF and coalesce the neighbouring bufs */
- for (cl = in;
- cl && vec.nelts < ngx_max_wsabufs && send < limit;
- cl = cl->next)
- {
+ for (cl = in; cl && send < limit; cl = cl->next) {
+
if (ngx_buf_special(cl->buf)) {
continue;
}
@@ -77,6 +75,10 @@
wsabuf->len += cl->buf->last - cl->buf->pos;
} else {
+ if (vec.nelts == vec.nalloc) {
+ break;
+ }
+
wsabuf = ngx_array_push(&vec);
if (wsabuf == NULL) {
return NGX_CHAIN_ERROR;
@@ -169,7 +171,7 @@
vec.elts = wsabufs;
vec.nelts = 0;
vec.size = sizeof(WSABUF);
- vec.nalloc = NGX_WSABUFS;
+ vec.nalloc = ngx_min(NGX_WSABUFS, ngx_max_wsabufs);
vec.pool = c->pool;
send = 0;
@@ -178,10 +180,8 @@
/* create the WSABUF and coalesce the neighbouring bufs */
- for (cl = in;
- cl && vec.nelts < ngx_max_wsabufs && send < limit;
- cl = cl->next)
- {
+ for (cl = in; cl && send < limit; cl = cl->next) {
+
if (ngx_buf_special(cl->buf)) {
continue;
}
@@ -196,6 +196,10 @@
wsabuf->len += cl->buf->last - cl->buf->pos;
} else {
+ if (vec.nelts == vec.nalloc) {
+ break;
+ }
+
wsabuf = ngx_array_push(&vec);
if (wsabuf == NULL) {
return NGX_CHAIN_ERROR;