Merge branch 'nginx' (nginx-1.19.2).
Change-Id: I1045719e4bb1eeb8d8b9a69d245d2371e5640393
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
diff --git a/.hgtags b/.hgtags
index 7c9513a..edcbdac 100644
--- a/.hgtags
+++ b/.hgtags
@@ -451,3 +451,4 @@
c44970de01474f6f3e01b0adea85ec1d03e3a5f2 release-1.17.10
cbe6ba650211541310618849168631ce0b788f35 release-1.19.0
062920e2f3bf871ef7a3d8496edec1b3065faf80 release-1.19.1
+a7b46539f507e6c64efa0efda69ad60b6f4ffbce release-1.19.2
diff --git a/BUILD b/BUILD
index bd6af32..8f78db1 100644
--- a/BUILD
+++ b/BUILD
@@ -1520,5 +1520,5 @@
preinst = "@nginx_pkgoss//:debian_preinst",
prerm = "@nginx_pkgoss//:debian_prerm",
section = "httpd",
- version = "1.19.1",
+ version = "1.19.2",
)
diff --git a/build.bzl b/build.bzl
index dd14d2b..beed032 100644
--- a/build.bzl
+++ b/build.bzl
@@ -673,9 +673,9 @@
name = "nginx_pkgoss",
build_file_content = _PKGOSS_BUILD_FILE.format(nginx = nginx) +
_PKGOSS_BUILD_FILE_TAIL,
- commit = "cfc029dae67e72379ec03a297648c6e6a3e71f0c", # nginx-1.19.1
+ commit = "d02e5c2fdd53ca365e688602851c8f89526b9404", # nginx-1.19.2
remote = "https://nginx.googlesource.com/nginx-pkgoss",
- shallow_since = "1594137158 +0300",
+ shallow_since = "1597157447 +0300",
)
def nginx_repositories_zlib(bind):
diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml
index 2f1bc48..2106c87 100644
--- a/docs/xml/nginx/changes.xml
+++ b/docs/xml/nginx/changes.xml
@@ -5,6 +5,108 @@
<change_log title="nginx">
+<changes ver="1.19.2" date="2020-08-11">
+
+<change type="change">
+<para lang="ru">
+теперь nginx начинает закрывать keepalive-соединения,
+не дожидаясь исчерпания всех свободных соединений,
+а также пишет об этом предупреждение в лог ошибок.
+</para>
+<para lang="en">
+now nginx starts closing keepalive connections
+before all free worker connections are exhausted,
+and logs a warning about this to the error log.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+оптимизация чтения тела запроса
+при использовании chunked transfer encoding.
+</para>
+<para lang="en">
+optimization of client request body reading
+when using chunked transfer encoding.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+утечки памяти при использовании директивы ssl_ocsp.
+</para>
+<para lang="en">
+memory leak if the "ssl_ocsp" directive was used.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+в логах могли появляться сообщения "zero size buf in output",
+если FastCGI-сервер возвращал некорректный ответ;
+ошибка появилась в 1.19.1.
+</para>
+<para lang="en">
+"zero size buf in output" alerts might appear in logs
+if a FastCGI server returned an incorrect response;
+the bug had appeared in 1.19.1.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+в рабочем процессе мог произойти segmentation fault,
+если размеры large_client_header_buffers отличались
+в разных виртуальных серверах.
+</para>
+<para lang="en">
+a segmentation fault might occur in a worker process
+if different large_client_header_buffers sizes were used
+in different virtual servers.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+SSL shutdown мог не работать.
+</para>
+<para lang="en">
+SSL shutdown might not work.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+в логах могли появляться сообщения
+"SSL_shutdown() failed (SSL: ... bad write retry)".
+</para>
+<para lang="en">
+"SSL_shutdown() failed (SSL: ... bad write retry)"
+messages might appear in logs.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+в модуле ngx_http_slice_module.
+</para>
+<para lang="en">
+in the ngx_http_slice_module.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+в модуле ngx_http_xslt_filter_module.
+</para>
+<para lang="en">
+in the ngx_http_xslt_filter_module.
+</para>
+</change>
+
+</changes>
+
+
<changes ver="1.19.1" date="2020-07-07">
<change type="change">
diff --git a/src/core/nginx.h b/src/core/nginx.h
index 24db599..1720d9e 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -13,8 +13,8 @@
#define NGINX_NAME "nginx"
#endif
-#define nginx_version 1019001
-#define NGINX_VERSION "1.19.1"
+#define nginx_version 1019002
+#define NGINX_VERSION "1.19.2"
#define NGINX_VER NGINX_NAME "/" NGINX_VERSION
#ifdef NGX_BUILD
diff --git a/src/core/ngx_buf.h b/src/core/ngx_buf.h
index 12781a7..4b66562 100644
--- a/src/core/ngx_buf.h
+++ b/src/core/ngx_buf.h
@@ -125,20 +125,20 @@
#define NGX_CHAIN_ERROR (ngx_chain_t *) NGX_ERROR
-#define ngx_buf_in_memory(b) (b->temporary || b->memory || b->mmap)
-#define ngx_buf_in_memory_only(b) (ngx_buf_in_memory(b) && !b->in_file)
+#define ngx_buf_in_memory(b) ((b)->temporary || (b)->memory || (b)->mmap)
+#define ngx_buf_in_memory_only(b) (ngx_buf_in_memory(b) && !(b)->in_file)
#define ngx_buf_special(b) \
- ((b->flush || b->last_buf || b->sync) \
- && !ngx_buf_in_memory(b) && !b->in_file)
+ (((b)->flush || (b)->last_buf || (b)->sync) \
+ && !ngx_buf_in_memory(b) && !(b)->in_file)
#define ngx_buf_sync_only(b) \
- (b->sync \
- && !ngx_buf_in_memory(b) && !b->in_file && !b->flush && !b->last_buf)
+ ((b)->sync && !ngx_buf_in_memory(b) \
+ && !(b)->in_file && !(b)->flush && !(b)->last_buf)
#define ngx_buf_size(b) \
- (ngx_buf_in_memory(b) ? (off_t) (b->last - b->pos): \
- (b->file_last - b->file_pos))
+ (ngx_buf_in_memory(b) ? (off_t) ((b)->last - (b)->pos): \
+ ((b)->file_last - (b)->file_pos))
ngx_buf_t *ngx_create_temp_buf(ngx_pool_t *pool, size_t size);
ngx_chain_t *ngx_create_chain_of_bufs(ngx_pool_t *pool, ngx_bufs_t *bufs);
@@ -149,8 +149,8 @@
ngx_chain_t *ngx_alloc_chain_link(ngx_pool_t *pool);
#define ngx_free_chain(pool, cl) \
- cl->next = pool->chain; \
- pool->chain = cl
+ (cl)->next = (pool)->chain; \
+ (pool)->chain = (cl)
diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c
index 88fefce..c082d0d 100644
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -1107,12 +1107,9 @@
return NULL;
}
- c = ngx_cycle->free_connections;
+ ngx_drain_connections((ngx_cycle_t *) ngx_cycle);
- if (c == NULL) {
- ngx_drain_connections((ngx_cycle_t *) ngx_cycle);
- c = ngx_cycle->free_connections;
- }
+ c = ngx_cycle->free_connections;
if (c == NULL) {
ngx_log_error(NGX_LOG_ALERT, log, 0,
@@ -1298,6 +1295,21 @@
ngx_queue_t *q;
ngx_connection_t *c;
+ if (cycle->free_connection_n > cycle->connection_n / 16
+ || cycle->reusable_connections_n == 0)
+ {
+ return;
+ }
+
+ if (cycle->connections_reuse_time != ngx_time()) {
+ cycle->connections_reuse_time = ngx_time();
+
+ ngx_log_error(NGX_LOG_WARN, cycle->log, 0,
+ "%ui worker_connections are not enough, "
+ "reusing connections",
+ cycle->connection_n);
+ }
+
n = ngx_max(ngx_min(32, cycle->reusable_connections_n / 8), 1);
for (i = 0; i < n; i++) {
diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c
index 764cf46..d7479fa 100644
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -1009,6 +1009,7 @@
ngx_create_pidfile(ngx_str_t *name, ngx_log_t *log)
{
size_t len;
+ ngx_int_t rc;
ngx_uint_t create;
ngx_file_t file;
u_char pid[NGX_INT64_LEN + 2];
@@ -1033,11 +1034,13 @@
return NGX_ERROR;
}
+ rc = NGX_OK;
+
if (!ngx_test_config) {
len = ngx_snprintf(pid, NGX_INT64_LEN + 2, "%P%N", ngx_pid) - pid;
if (ngx_write_file(&file, pid, len, 0) == NGX_ERROR) {
- return NGX_ERROR;
+ rc = NGX_ERROR;
}
}
@@ -1046,7 +1049,7 @@
ngx_close_file_n " \"%s\" failed", file.name.data);
}
- return NGX_OK;
+ return rc;
}
diff --git a/src/core/ngx_cycle.h b/src/core/ngx_cycle.h
index 57bfd89..f24ec43 100644
--- a/src/core/ngx_cycle.h
+++ b/src/core/ngx_cycle.h
@@ -55,6 +55,7 @@
ngx_queue_t reusable_connections_queue;
ngx_uint_t reusable_connections_n;
+ time_t connections_reuse_time;
ngx_array_t listening;
ngx_array_t paths;
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index 33af90a..9bf976a 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -2797,8 +2797,9 @@
ngx_int_t
ngx_ssl_shutdown(ngx_connection_t *c)
{
- int n, sslerr, mode;
- ngx_err_t err;
+ int n, sslerr, mode;
+ ngx_err_t err;
+ ngx_uint_t tries;
ngx_ssl_ocsp_cleanup(c);
@@ -2839,55 +2840,71 @@
ngx_ssl_clear_error(c->log);
- n = SSL_shutdown(c->ssl->connection);
+ tries = 2;
- ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n);
+ for ( ;; ) {
- sslerr = 0;
+ /*
+ * For bidirectional shutdown, SSL_shutdown() needs to be called
+ * twice: first call sends the "close notify" alert and returns 0,
+ * second call waits for the peer's "close notify" alert.
+ */
- /* before 0.9.8m SSL_shutdown() returned 0 instead of -1 on errors */
+ n = SSL_shutdown(c->ssl->connection);
- if (n != 1 && ERR_peek_error()) {
+ 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;
+
+ return NGX_OK;
+ }
+
+ if (n == 0 && tries-- > 1) {
+ continue;
+ }
+
+ /* before 0.9.8m SSL_shutdown() returned 0 instead of -1 on errors */
+
sslerr = SSL_get_error(c->ssl->connection, n);
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"SSL_get_error: %d", sslerr);
- }
- if (n == 1 || sslerr == 0 || sslerr == SSL_ERROR_ZERO_RETURN) {
+ if (sslerr == SSL_ERROR_WANT_READ || sslerr == SSL_ERROR_WANT_WRITE) {
+ c->read->handler = ngx_ssl_shutdown_handler;
+ c->write->handler = ngx_ssl_shutdown_handler;
+
+ if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ ngx_add_timer(c->read, 3000);
+
+ return NGX_AGAIN;
+ }
+
+ if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) {
+ SSL_free(c->ssl->connection);
+ c->ssl = NULL;
+
+ return NGX_OK;
+ }
+
+ 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;
- return NGX_OK;
+ return NGX_ERROR;
}
-
- if (sslerr == SSL_ERROR_WANT_READ || sslerr == SSL_ERROR_WANT_WRITE) {
- c->read->handler = ngx_ssl_shutdown_handler;
- c->write->handler = ngx_ssl_shutdown_handler;
-
- if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
- return NGX_ERROR;
- }
-
- if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
- return NGX_ERROR;
- }
-
- if (sslerr == SSL_ERROR_WANT_READ) {
- ngx_add_timer(c->read, 30000);
- }
-
- return NGX_AGAIN;
- }
-
- 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;
-
- return NGX_ERROR;
}
diff --git a/src/event/ngx_event_openssl_stapling.c b/src/event/ngx_event_openssl_stapling.c
index 0e79d6c..9d92421 100644
--- a/src/event/ngx_event_openssl_stapling.c
+++ b/src/event/ngx_event_openssl_stapling.c
@@ -883,6 +883,7 @@
ocsp = ngx_pcalloc(c->pool, sizeof(ngx_ssl_ocsp_t));
if (ocsp == NULL) {
+ X509_free(cert);
return NGX_ERROR;
}
@@ -899,6 +900,7 @@
if (ocsp->certs) {
ocsp->certs = X509_chain_up_ref(ocsp->certs);
if (ocsp->certs == NULL) {
+ X509_free(cert);
return NGX_ERROR;
}
}
@@ -910,6 +912,7 @@
if (store == NULL) {
ngx_ssl_error(NGX_LOG_ERR, c->log, 0,
"SSL_CTX_get_cert_store() failed");
+ X509_free(cert);
return NGX_ERROR;
}
@@ -917,6 +920,7 @@
if (store_ctx == NULL) {
ngx_ssl_error(NGX_LOG_ERR, c->log, 0,
"X509_STORE_CTX_new() failed");
+ X509_free(cert);
return NGX_ERROR;
}
@@ -926,6 +930,7 @@
ngx_ssl_error(NGX_LOG_ERR, c->log, 0,
"X509_STORE_CTX_init() failed");
X509_STORE_CTX_free(store_ctx);
+ X509_free(cert);
return NGX_ERROR;
}
@@ -933,6 +938,7 @@
if (rc <= 0) {
ngx_ssl_error(NGX_LOG_ERR, c->log, 0, "X509_verify_cert() failed");
X509_STORE_CTX_free(store_ctx);
+ X509_free(cert);
return NGX_ERROR;
}
@@ -941,12 +947,15 @@
ngx_ssl_error(NGX_LOG_ERR, c->log, 0,
"X509_STORE_CTX_get1_chain() failed");
X509_STORE_CTX_free(store_ctx);
+ X509_free(cert);
return NGX_ERROR;
}
X509_STORE_CTX_free(store_ctx);
}
+ X509_free(cert);
+
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"ssl ocsp validate, certs:%d", sk_X509_num(ocsp->certs));
diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c
index e50d1a7..5191880 100644
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -2306,6 +2306,18 @@
break;
}
+ if (f->rest == -2) {
+ f->rest = r->upstream->headers_in.content_length_n;
+ }
+
+ if (f->rest == 0) {
+ ngx_log_error(NGX_LOG_WARN, p->log, 0,
+ "upstream sent more data than specified in "
+ "\"Content-Length\" header");
+ p->upstream_done = 1;
+ break;
+ }
+
cl = ngx_chain_get_free_buf(p->pool, &p->free);
if (cl == NULL) {
return NGX_ERROR;
@@ -2349,11 +2361,7 @@
b->last = f->last;
}
- if (f->rest == -2) {
- f->rest = r->upstream->headers_in.content_length_n;
- }
-
- if (f->rest >= 0) {
+ if (f->rest > 0) {
if (b->last - b->pos > f->rest) {
ngx_log_error(NGX_LOG_WARN, p->log, 0,
@@ -2564,6 +2572,14 @@
break;
}
+ if (f->rest == 0) {
+ ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
+ "upstream sent more data than specified in "
+ "\"Content-Length\" header");
+ u->length = 0;
+ break;
+ }
+
cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
if (cl == NULL) {
return NGX_ERROR;
@@ -2594,7 +2610,7 @@
b->last = f->last;
}
- if (f->rest >= 0) {
+ if (f->rest > 0) {
if (b->last - b->pos > f->rest) {
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
diff --git a/src/http/modules/ngx_http_slice_filter_module.c b/src/http/modules/ngx_http_slice_filter_module.c
index c1edbca..186380a 100644
--- a/src/http/modules/ngx_http_slice_filter_module.c
+++ b/src/http/modules/ngx_http_slice_filter_module.c
@@ -180,6 +180,11 @@
r->headers_out.content_range->hash = 0;
r->headers_out.content_range = NULL;
+ if (r->headers_out.accept_ranges) {
+ r->headers_out.accept_ranges->hash = 0;
+ r->headers_out.accept_ranges = NULL;
+ }
+
r->allow_ranges = 1;
r->subrequest_ranges = 1;
r->single_range = 1;
diff --git a/src/http/modules/ngx_http_xslt_filter_module.c b/src/http/modules/ngx_http_xslt_filter_module.c
index b2f107d..8afd656 100644
--- a/src/http/modules/ngx_http_xslt_filter_module.c
+++ b/src/http/modules/ngx_http_xslt_filter_module.c
@@ -233,6 +233,7 @@
ngx_http_set_ctx(r, ctx, ngx_http_xslt_filter_module);
r->main_filter_need_in_memory = 1;
+ r->allow_ranges = 0;
return NGX_OK;
}
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index c28844d..e8dbb03 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -1802,6 +1802,12 @@
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http large header copy: %uz", r->header_in->pos - old);
+ if (r->header_in->pos - old > b->end - b->start) {
+ ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+ "too large header to copy");
+ return NGX_ERROR;
+ }
+
new = b->start;
ngx_memcpy(new, old, r->header_in->pos - old);
@@ -3157,6 +3163,12 @@
rev->error = 1;
}
+#if (NGX_HTTP_SSL)
+ if (c->ssl) {
+ c->ssl->no_send_shutdown = 1;
+ }
+#endif
+
ngx_log_error(NGX_LOG_INFO, c->log, err,
"client prematurely closed connection");
diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c
index c4f092e..71d7e9a 100644
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -12,6 +12,8 @@
static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r);
static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r);
+static ngx_int_t ngx_http_copy_pipelined_header(ngx_http_request_t *r,
+ ngx_buf_t *buf);
static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r);
static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r);
static ngx_int_t ngx_http_discard_request_body_filter(ngx_http_request_t *r,
@@ -282,28 +284,12 @@
for ( ;; ) {
if (rb->buf->last == rb->buf->end) {
- if (rb->buf->pos != rb->buf->last) {
+ /* update chains */
- /* pass buffer to request body filter chain */
+ rc = ngx_http_request_body_filter(r, NULL);
- out.buf = rb->buf;
- out.next = NULL;
-
- rc = ngx_http_request_body_filter(r, &out);
-
- if (rc != NGX_OK) {
- return rc;
- }
-
- } else {
-
- /* update chains */
-
- rc = ngx_http_request_body_filter(r, NULL);
-
- if (rc != NGX_OK) {
- return rc;
- }
+ if (rc != NGX_OK) {
+ return rc;
}
if (rb->busy != NULL) {
@@ -355,17 +341,15 @@
rb->buf->last += n;
r->request_length += n;
- if (n == rest) {
- /* pass buffer to request body filter chain */
+ /* pass buffer to request body filter chain */
- out.buf = rb->buf;
- out.next = NULL;
+ out.buf = rb->buf;
+ out.next = NULL;
- rc = ngx_http_request_body_filter(r, &out);
+ rc = ngx_http_request_body_filter(r, &out);
- if (rc != NGX_OK) {
- return rc;
- }
+ if (rc != NGX_OK) {
+ return rc;
}
if (rb->rest == 0) {
@@ -386,21 +370,6 @@
if (!c->read->ready) {
- if (r->request_body_no_buffering
- && rb->buf->pos != rb->buf->last)
- {
- /* pass buffer to request body filter chain */
-
- out.buf = rb->buf;
- out.next = NULL;
-
- rc = ngx_http_request_body_filter(r, &out);
-
- if (rc != NGX_OK) {
- return rc;
- }
- }
-
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
ngx_add_timer(c->read, clcf->client_body_timeout);
@@ -412,6 +381,10 @@
}
}
+ if (ngx_http_copy_pipelined_header(r, rb->buf) != NGX_OK) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
if (c->read->timer_set) {
ngx_del_timer(c->read);
}
@@ -426,6 +399,88 @@
static ngx_int_t
+ngx_http_copy_pipelined_header(ngx_http_request_t *r, ngx_buf_t *buf)
+{
+ size_t n;
+ ngx_buf_t *b;
+ ngx_chain_t *cl;
+ ngx_http_connection_t *hc;
+ ngx_http_core_srv_conf_t *cscf;
+
+ b = r->header_in;
+ n = buf->last - buf->pos;
+
+ if (buf == b || n == 0) {
+ return NGX_OK;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http body pipelined header: %uz", n);
+
+ /*
+ * if there is a pipelined request in the client body buffer,
+ * copy it to the r->header_in buffer if there is enough room,
+ * or allocate a large client header buffer
+ */
+
+ if (n > (size_t) (b->end - b->last)) {
+
+ hc = r->http_connection;
+
+ if (hc->free) {
+ cl = hc->free;
+ hc->free = cl->next;
+
+ b = cl->buf;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http large header free: %p %uz",
+ b->pos, b->end - b->last);
+
+ } else {
+ cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
+
+ b = ngx_create_temp_buf(r->connection->pool,
+ cscf->large_client_header_buffers.size);
+ if (b == NULL) {
+ return NGX_ERROR;
+ }
+
+ cl = ngx_alloc_chain_link(r->connection->pool);
+ if (cl == NULL) {
+ return NGX_ERROR;
+ }
+
+ cl->buf = b;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http large header alloc: %p %uz",
+ b->pos, b->end - b->last);
+ }
+
+ cl->next = hc->busy;
+ hc->busy = cl;
+ hc->nbusy++;
+
+ r->header_in = b;
+
+ if (n > (size_t) (b->end - b->last)) {
+ ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+ "too large pipelined header after reading body");
+ return NGX_ERROR;
+ }
+ }
+
+ ngx_memcpy(b->last, buf->pos, n);
+
+ b->last += n;
+ r->request_length -= n;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
ngx_http_write_request_body(ngx_http_request_t *r)
{
ssize_t n;
@@ -670,8 +725,7 @@
for ( ;; ) {
if (r->headers_in.content_length_n == 0) {
- r->read_event_handler = ngx_http_block_reading;
- return NGX_OK;
+ break;
}
if (!r->connection->read->ready) {
@@ -705,15 +759,24 @@
return rc;
}
}
+
+ if (ngx_http_copy_pipelined_header(r, &b) != NGX_OK) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ r->read_event_handler = ngx_http_block_reading;
+
+ return NGX_OK;
}
static ngx_int_t
ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b)
{
- size_t size;
- ngx_int_t rc;
- ngx_http_request_body_t *rb;
+ size_t size;
+ ngx_int_t rc;
+ ngx_http_request_body_t *rb;
+ ngx_http_core_srv_conf_t *cscf;
if (r->headers_in.chunked) {
@@ -768,7 +831,10 @@
/* set amount of data we want to see next time */
- r->headers_in.content_length_n = rb->chunked->length;
+ cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
+
+ r->headers_in.content_length_n = ngx_max(rb->chunked->length,
+ (off_t) cscf->large_client_header_buffers.size);
break;
}
@@ -936,6 +1002,7 @@
ngx_chain_t *cl, *out, *tl, **ll;
ngx_http_request_body_t *rb;
ngx_http_core_loc_conf_t *clcf;
+ ngx_http_core_srv_conf_t *cscf;
rb = r->request_body;
@@ -949,8 +1016,10 @@
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
+ cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
+
r->headers_in.content_length_n = 0;
- rb->rest = 3;
+ rb->rest = cscf->large_client_header_buffers.size;
}
out = NULL;
@@ -958,6 +1027,8 @@
for (cl = in; cl; cl = cl->next) {
+ b = NULL;
+
for ( ;; ) {
ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
@@ -992,6 +1063,29 @@
return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
}
+ if (b
+ && rb->chunked->size <= 128
+ && cl->buf->last - cl->buf->pos >= rb->chunked->size)
+ {
+ r->headers_in.content_length_n += rb->chunked->size;
+
+ if (rb->chunked->size < 8) {
+
+ while (rb->chunked->size) {
+ *b->last++ = *cl->buf->pos++;
+ rb->chunked->size--;
+ }
+
+ } else {
+ ngx_memmove(b->last, cl->buf->pos, rb->chunked->size);
+ b->last += rb->chunked->size;
+ cl->buf->pos += rb->chunked->size;
+ rb->chunked->size = 0;
+ }
+
+ continue;
+ }
+
tl = ngx_chain_get_free_buf(r->pool, &rb->free);
if (tl == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -1057,7 +1151,10 @@
/* set rb->rest, amount of data we want to see next time */
- rb->rest = rb->chunked->length;
+ cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
+
+ rb->rest = ngx_max(rb->chunked->length,
+ (off_t) cscf->large_client_header_buffers.size);
break;
}
diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
index c013756..90dcfd4 100644
--- a/src/http/v2/ngx_http_v2.c
+++ b/src/http/v2/ngx_http_v2.c
@@ -476,6 +476,7 @@
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http2 write event timed out");
c->error = 1;
+ c->timedout = 1;
ngx_http_v2_finalize_connection(h2c, 0);
return;
}