aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Kandaurov <pluknet@nginx.com>2020-07-13 15:34:22 +0300
committerSergey Kandaurov <pluknet@nginx.com>2020-07-13 15:34:22 +0300
commit2346ee29e1333c20b9a9f9e5ea73940237fbff02 (patch)
tree9f7249e4871fe9a13799df5e16abbaa2ebd065ff /src
parent3db00b4da74ddc0872be4cdb836aaff7fc21272a (diff)
parent1b2f040a1f82dfd3b30d3b67ea57b3bf1d723d4d (diff)
downloadnginx-2346ee29e1333c20b9a9f9e5ea73940237fbff02.tar.gz
nginx-2346ee29e1333c20b9a9f9e5ea73940237fbff02.zip
Merged with the default branch.
Diffstat (limited to 'src')
-rw-r--r--src/core/nginx.c1
-rw-r--r--src/core/nginx.h4
-rw-r--r--src/core/ngx_connection.c3
-rw-r--r--src/core/ngx_cycle.c1
-rw-r--r--src/event/ngx_event_openssl.c3
-rw-r--r--src/event/ngx_event_openssl_stapling.c41
-rw-r--r--src/event/ngx_event_pipe.c28
-rw-r--r--src/http/modules/ngx_http_fastcgi_module.c120
-rw-r--r--src/http/modules/ngx_http_grpc_module.c39
-rw-r--r--src/http/modules/ngx_http_memcached_module.c9
-rw-r--r--src/http/modules/ngx_http_proxy_module.c87
-rw-r--r--src/http/modules/ngx_http_scgi_module.c36
-rw-r--r--src/http/modules/ngx_http_uwsgi_module.c37
-rw-r--r--src/http/ngx_http.c4
-rw-r--r--src/http/ngx_http_cache.h1
-rw-r--r--src/http/ngx_http_file_cache.c43
-rw-r--r--src/http/ngx_http_upstream.c22
-rw-r--r--src/http/ngx_http_upstream.h3
-rw-r--r--src/http/v2/ngx_http_v2.c128
-rw-r--r--src/http/v2/ngx_http_v2.h2
-rw-r--r--src/os/unix/ngx_files.c45
-rw-r--r--src/os/unix/ngx_files.h6
-rw-r--r--src/os/unix/ngx_process_cycle.c14
-rw-r--r--src/os/unix/ngx_udp_sendmsg_chain.c7
-rw-r--r--src/os/win32/ngx_files.c13
-rw-r--r--src/os/win32/ngx_files.h1
-rw-r--r--src/stream/ngx_stream_proxy_module.c3
-rw-r--r--src/stream/ngx_stream_write_filter_module.c3
28 files changed, 618 insertions, 86 deletions
diff --git a/src/core/nginx.c b/src/core/nginx.c
index 9fcb0eb23..f73e5598e 100644
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -492,6 +492,7 @@ ngx_add_inherited_sockets(ngx_cycle_t *cycle)
ngx_memzero(ls, sizeof(ngx_listening_t));
ls->fd = (ngx_socket_t) s;
+ ls->inherited = 1;
}
}
diff --git a/src/core/nginx.h b/src/core/nginx.h
index 0085c5c65..49d35c2b9 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -9,8 +9,8 @@
#define _NGINX_H_INCLUDED_
-#define nginx_version 1019000
-#define NGINX_VERSION "1.19.0"
+#define nginx_version 1019001
+#define NGINX_VERSION "1.19.1"
#define NGINX_VER "nginx/" NGINX_VERSION
#ifdef NGX_BUILD
diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c
index 5bae54502..ba07c63e8 100644
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -1074,7 +1074,8 @@ ngx_close_listening_sockets(ngx_cycle_t *cycle)
if (ls[i].sockaddr->sa_family == AF_UNIX
&& ngx_process <= NGX_PROCESS_MASTER
- && ngx_new_binary == 0)
+ && ngx_new_binary == 0
+ && (!ls[i].inherited || ngx_getppid() != ngx_parent))
{
u_char *name = ls[i].addr_text.data + sizeof("unix:") - 1;
diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c
index 95f4bdfab..764cf46ba 100644
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -520,6 +520,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
== NGX_OK)
{
nls[n].fd = ls[i].fd;
+ nls[n].inherited = ls[i].inherited;
nls[n].previous = &ls[i];
ls[i].remain = 1;
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index 1777a5cfc..a5188dc0e 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -920,6 +920,9 @@ ngx_int_t
ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
ngx_int_t depth)
{
+ SSL_CTX_set_verify(ssl->ctx, SSL_CTX_get_verify_mode(ssl->ctx),
+ ngx_ssl_verify_callback);
+
SSL_CTX_set_verify_depth(ssl->ctx, depth);
if (cert->len == 0) {
diff --git a/src/event/ngx_event_openssl_stapling.c b/src/event/ngx_event_openssl_stapling.c
index a0a63c165..0e79d6cc4 100644
--- a/src/event/ngx_event_openssl_stapling.c
+++ b/src/event/ngx_event_openssl_stapling.c
@@ -980,6 +980,7 @@ ngx_ssl_ocsp_validate_next(ngx_connection_t *c)
if (ocsp->ncert == n - 1 || (ocf->depth == 2 && ocsp->ncert == 1)) {
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"ssl ocsp validated, certs:%ui", ocsp->ncert);
+ rc = NGX_OK;
goto done;
}
@@ -988,7 +989,8 @@ ngx_ssl_ocsp_validate_next(ngx_connection_t *c)
ctx = ngx_ssl_ocsp_start(c->log);
if (ctx == NULL) {
- goto failed;
+ rc = NGX_ERROR;
+ goto done;
}
ocsp->ctx = ctx;
@@ -1012,8 +1014,9 @@ ngx_ssl_ocsp_validate_next(ngx_connection_t *c)
ctx->uri = ocf->uri;
ctx->port = ocf->port;
- if (ngx_ssl_ocsp_responder(c, ctx) != NGX_OK) {
- goto failed;
+ rc = ngx_ssl_ocsp_responder(c, ctx);
+ if (rc != NGX_OK) {
+ goto done;
}
if (ctx->uri.len == 0) {
@@ -1025,7 +1028,7 @@ ngx_ssl_ocsp_validate_next(ngx_connection_t *c)
rc = ngx_ssl_ocsp_cache_lookup(ctx);
if (rc == NGX_ERROR) {
- goto failed;
+ goto done;
}
if (rc == NGX_DECLINED) {
@@ -1051,12 +1054,12 @@ ngx_ssl_ocsp_validate_next(ngx_connection_t *c)
done:
- ocsp->status = NGX_OK;
- return;
-
-failed:
+ ocsp->status = rc;
- ocsp->status = NGX_ERROR;
+ if (c->ssl->in_ocsp) {
+ c->ssl->handshaked = 1;
+ c->ssl->handler(c);
+ }
}
@@ -1073,22 +1076,16 @@ ngx_ssl_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx)
rc = ngx_ssl_ocsp_verify(ctx);
if (rc != NGX_OK) {
- ocsp->status = rc;
- ngx_ssl_ocsp_done(ctx);
goto done;
}
rc = ngx_ssl_ocsp_cache_store(ctx);
if (rc != NGX_OK) {
- ocsp->status = rc;
- ngx_ssl_ocsp_done(ctx);
goto done;
}
if (ctx->status != V_OCSP_CERTSTATUS_GOOD) {
ocsp->cert_status = ctx->status;
- ocsp->status = NGX_OK;
- ngx_ssl_ocsp_done(ctx);
goto done;
}
@@ -1096,15 +1093,17 @@ ngx_ssl_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx)
ngx_ssl_ocsp_validate_next(c);
-done:
+ return;
- if (ocsp->status == NGX_AGAIN || !c->ssl->in_ocsp) {
- return;
- }
+done:
- c->ssl->handshaked = 1;
+ ocsp->status = rc;
+ ngx_ssl_ocsp_done(ctx);
- c->ssl->handler(c);
+ if (c->ssl->in_ocsp) {
+ c->ssl->handshaked = 1;
+ c->ssl->handler(c);
+ }
}
diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c
index 531b13aad..54412e130 100644
--- a/src/event/ngx_event_pipe.c
+++ b/src/event/ngx_event_pipe.c
@@ -960,6 +960,22 @@ ngx_event_pipe_copy_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
return NGX_OK;
}
+ if (p->upstream_done) {
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0,
+ "input data after close");
+ return NGX_OK;
+ }
+
+ if (p->length == 0) {
+ p->upstream_done = 1;
+
+ ngx_log_error(NGX_LOG_WARN, p->log, 0,
+ "upstream sent more data than specified in "
+ "\"Content-Length\" header");
+
+ return NGX_OK;
+ }
+
cl = ngx_chain_get_free_buf(p->pool, &p->free);
if (cl == NULL) {
return NGX_ERROR;
@@ -987,6 +1003,18 @@ ngx_event_pipe_copy_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
return NGX_OK;
}
+ if (b->last - b->pos > p->length) {
+
+ ngx_log_error(NGX_LOG_WARN, p->log, 0,
+ "upstream sent more data than specified in "
+ "\"Content-Length\" header");
+
+ b->last = b->pos + p->length;
+ p->upstream_done = 1;
+
+ return NGX_OK;
+ }
+
p->length -= b->last - b->pos;
return NGX_OK;
diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c
index 2be067214..e50d1a70d 100644
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -81,12 +81,15 @@ typedef struct {
size_t length;
size_t padding;
+ off_t rest;
+
ngx_chain_t *free;
ngx_chain_t *busy;
unsigned fastcgi_stdout:1;
unsigned large_stderr:1;
unsigned header_sent:1;
+ unsigned closed:1;
ngx_array_t *split_parts;
@@ -2075,13 +2078,31 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r)
static ngx_int_t
ngx_http_fastcgi_input_filter_init(void *data)
{
- ngx_http_request_t *r = data;
+ ngx_http_request_t *r = data;
+
+ ngx_http_upstream_t *u;
+ ngx_http_fastcgi_ctx_t *f;
ngx_http_fastcgi_loc_conf_t *flcf;
+ u = r->upstream;
+
+ f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
- r->upstream->pipe->length = flcf->keep_conn ?
- (off_t) sizeof(ngx_http_fastcgi_header_t) : -1;
+ u->pipe->length = flcf->keep_conn ?
+ (off_t) sizeof(ngx_http_fastcgi_header_t) : -1;
+
+ if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
+ || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED)
+ {
+ f->rest = 0;
+
+ } else if (r->method == NGX_HTTP_HEAD) {
+ f->rest = -2;
+
+ } else {
+ f->rest = u->headers_in.content_length_n;
+ }
return NGX_OK;
}
@@ -2106,6 +2127,15 @@ ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
+ if (p->upstream_done || f->closed) {
+ r->upstream->keepalive = 0;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
+ "http fastcgi data after close");
+
+ return NGX_OK;
+ }
+
b = NULL;
prev = &buf->shadow;
@@ -2128,13 +2158,25 @@ ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) {
f->state = ngx_http_fastcgi_st_padding;
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
+ "http fastcgi closed stdout");
+
+ if (f->rest > 0) {
+ ngx_log_error(NGX_LOG_ERR, p->log, 0,
+ "upstream prematurely closed "
+ "FastCGI stdout");
+
+ p->upstream_error = 1;
+ p->upstream_eof = 0;
+ f->closed = 1;
+
+ break;
+ }
+
if (!flcf->keep_conn) {
p->upstream_done = 1;
}
- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
- "http fastcgi closed stdout");
-
continue;
}
@@ -2143,6 +2185,18 @@ ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
"http fastcgi sent end request");
+ if (f->rest > 0) {
+ ngx_log_error(NGX_LOG_ERR, p->log, 0,
+ "upstream prematurely closed "
+ "FastCGI request");
+
+ p->upstream_error = 1;
+ p->upstream_eof = 0;
+ f->closed = 1;
+
+ break;
+ }
+
if (!flcf->keep_conn) {
p->upstream_done = 1;
break;
@@ -2289,15 +2343,31 @@ ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
f->pos += f->length;
b->last = f->pos;
- continue;
+ } else {
+ f->length -= f->last - f->pos;
+ f->pos = f->last;
+ b->last = f->last;
}
- f->length -= f->last - f->pos;
+ if (f->rest == -2) {
+ f->rest = r->upstream->headers_in.content_length_n;
+ }
- b->last = f->last;
+ if (f->rest >= 0) {
- break;
+ if (b->last - b->pos > f->rest) {
+ ngx_log_error(NGX_LOG_WARN, p->log, 0,
+ "upstream sent more data than specified in "
+ "\"Content-Length\" header");
+
+ b->last = b->pos + f->rest;
+ p->upstream_done = 1;
+
+ break;
+ }
+ f->rest -= b->last - b->pos;
+ }
}
if (flcf->keep_conn) {
@@ -2391,6 +2461,14 @@ ngx_http_fastcgi_non_buffered_filter(void *data, ssize_t bytes)
if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
+ if (f->rest > 0) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "upstream prematurely closed "
+ "FastCGI request");
+ u->error = 1;
+ break;
+ }
+
if (f->pos + f->padding < f->last) {
u->length = 0;
break;
@@ -2510,13 +2588,27 @@ ngx_http_fastcgi_non_buffered_filter(void *data, ssize_t bytes)
f->pos += f->length;
b->last = f->pos;
- continue;
+ } else {
+ f->length -= f->last - f->pos;
+ f->pos = f->last;
+ b->last = f->last;
}
- f->length -= f->last - f->pos;
- b->last = f->last;
+ if (f->rest >= 0) {
+
+ if (b->last - b->pos > f->rest) {
+ ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
+ "upstream sent more data than specified in "
+ "\"Content-Length\" header");
- break;
+ b->last = b->pos + f->rest;
+ u->length = 0;
+
+ break;
+ }
+
+ f->rest -= b->last - b->pos;
+ }
}
return NGX_OK;
diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c
index 992211e73..ab4ad6be1 100644
--- a/src/http/modules/ngx_http_grpc_module.c
+++ b/src/http/modules/ngx_http_grpc_module.c
@@ -84,6 +84,8 @@ typedef struct {
ngx_uint_t pings;
ngx_uint_t settings;
+ off_t length;
+
ssize_t send_window;
size_t recv_window;
@@ -1953,10 +1955,28 @@ ngx_http_grpc_filter_init(void *data)
r = ctx->request;
u = r->upstream;
- u->length = 1;
+ if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
+ || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
+ || r->method == NGX_HTTP_HEAD)
+ {
+ ctx->length = 0;
+
+ } else {
+ ctx->length = u->headers_in.content_length_n;
+ }
if (ctx->end_stream) {
+
+ if (ctx->length > 0) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "upstream prematurely closed stream");
+ return NGX_ERROR;
+ }
+
u->length = 0;
+
+ } else {
+ u->length = 1;
}
return NGX_OK;
@@ -1999,6 +2019,12 @@ ngx_http_grpc_filter(void *data, ssize_t bytes)
if (ctx->done) {
+ if (ctx->length > 0) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "upstream prematurely closed stream");
+ return NGX_ERROR;
+ }
+
/*
* We have finished parsing the response and the
* remaining control frames. If there are unsent
@@ -2052,6 +2078,17 @@ ngx_http_grpc_filter(void *data, ssize_t bytes)
return NGX_ERROR;
}
+ if (ctx->length != -1) {
+ if ((off_t) ctx->rest > ctx->length) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "upstream sent response body larger "
+ "than indicated content length");
+ return NGX_ERROR;
+ }
+
+ ctx->length -= ctx->rest;
+ }
+
if (ctx->rest > ctx->recv_window) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream violated stream flow control, "
diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c
index 775bd7e81..c82df6e33 100644
--- a/src/http/modules/ngx_http_memcached_module.c
+++ b/src/http/modules/ngx_http_memcached_module.c
@@ -485,10 +485,11 @@ ngx_http_memcached_filter(void *data, ssize_t bytes)
if (u->length == (ssize_t) ctx->rest) {
- if (ngx_strncmp(b->last,
+ if (bytes > u->length
+ || ngx_strncmp(b->last,
ngx_http_memcached_end + NGX_HTTP_MEMCACHED_END - ctx->rest,
bytes)
- != 0)
+ != 0)
{
ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0,
"memcached sent invalid trailer");
@@ -540,7 +541,9 @@ ngx_http_memcached_filter(void *data, ssize_t bytes)
last += (size_t) (u->length - NGX_HTTP_MEMCACHED_END);
- if (ngx_strncmp(last, ngx_http_memcached_end, b->last - last) != 0) {
+ if (bytes > u->length
+ || ngx_strncmp(last, ngx_http_memcached_end, b->last - last) != 0)
+ {
ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0,
"memcached sent invalid trailer");
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index 3aafb9996..6cf2cbde0 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -2015,6 +2015,25 @@ ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
return NGX_OK;
}
+ if (p->upstream_done) {
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
+ "http proxy data after close");
+ return NGX_OK;
+ }
+
+ if (p->length == 0) {
+
+ ngx_log_error(NGX_LOG_WARN, p->log, 0,
+ "upstream sent more data than specified in "
+ "\"Content-Length\" header");
+
+ r = p->input_ctx;
+ r->upstream->keepalive = 0;
+ p->upstream_done = 1;
+
+ return NGX_OK;
+ }
+
cl = ngx_chain_get_free_buf(p->pool, &p->free);
if (cl == NULL) {
return NGX_ERROR;
@@ -2042,20 +2061,23 @@ ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
return NGX_OK;
}
+ if (b->last - b->pos > p->length) {
+
+ ngx_log_error(NGX_LOG_WARN, p->log, 0,
+ "upstream sent more data than specified in "
+ "\"Content-Length\" header");
+
+ b->last = b->pos + p->length;
+ p->upstream_done = 1;
+
+ return NGX_OK;
+ }
+
p->length -= b->last - b->pos;
if (p->length == 0) {
r = p->input_ctx;
- p->upstream_done = 1;
r->upstream->keepalive = !r->upstream->headers_in.connection_close;
-
- } else if (p->length < 0) {
- r = p->input_ctx;
- p->upstream_done = 1;
-
- ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
- "upstream sent more data than specified in "
- "\"Content-Length\" header");
}
return NGX_OK;
@@ -2082,6 +2104,23 @@ ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
return NGX_ERROR;
}
+ if (p->upstream_done) {
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
+ "http proxy data after close");
+ return NGX_OK;
+ }
+
+ if (p->length == 0) {
+
+ ngx_log_error(NGX_LOG_WARN, p->log, 0,
+ "upstream sent data after final chunk");
+
+ r->upstream->keepalive = 0;
+ p->upstream_done = 1;
+
+ return NGX_OK;
+ }
+
b = NULL;
prev = &buf->shadow;
@@ -2144,9 +2183,15 @@ ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
/* a whole response has been parsed successfully */
- p->upstream_done = 1;
+ p->length = 0;
r->upstream->keepalive = !r->upstream->headers_in.connection_close;
+ if (buf->pos != buf->last) {
+ ngx_log_error(NGX_LOG_WARN, p->log, 0,
+ "upstream sent data after final chunk");
+ r->upstream->keepalive = 0;
+ }
+
break;
}
@@ -2161,13 +2206,13 @@ ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
/* invalid response */
- ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ ngx_log_error(NGX_LOG_ERR, p->log, 0,
"upstream sent invalid chunked response");
return NGX_ERROR;
}
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, p->log, 0,
"http proxy chunked state %ui, length %O",
ctx->chunked.state, p->length);
@@ -2227,6 +2272,18 @@ ngx_http_proxy_non_buffered_copy_filter(void *data, ssize_t bytes)
return NGX_OK;
}
+ if (bytes > u->length) {
+
+ ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
+ "upstream sent more data than specified in "
+ "\"Content-Length\" header");
+
+ cl->buf->last = cl->buf->pos + u->length;
+ u->length = 0;
+
+ return NGX_OK;
+ }
+
u->length -= bytes;
if (u->length == 0) {
@@ -2313,6 +2370,12 @@ ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes)
u->keepalive = !u->headers_in.connection_close;
u->length = 0;
+ if (buf->pos != buf->last) {
+ ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
+ "upstream sent data after final chunk");
+ u->keepalive = 0;
+ }
+
break;
}
diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c
index 7216f781d..600999c88 100644
--- a/src/http/modules/ngx_http_scgi_module.c
+++ b/src/http/modules/ngx_http_scgi_module.c
@@ -49,6 +49,7 @@ static ngx_int_t ngx_http_scgi_create_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_scgi_reinit_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_scgi_process_status_line(ngx_http_request_t *r);
static ngx_int_t ngx_http_scgi_process_header(ngx_http_request_t *r);
+static ngx_int_t ngx_http_scgi_input_filter_init(void *data);
static void ngx_http_scgi_abort_request(ngx_http_request_t *r);
static void ngx_http_scgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc);
@@ -534,6 +535,10 @@ ngx_http_scgi_handler(ngx_http_request_t *r)
u->pipe->input_filter = ngx_event_pipe_copy_input_filter;
u->pipe->input_ctx = r;
+ u->input_filter_init = ngx_http_scgi_input_filter_init;
+ u->input_filter = ngx_http_upstream_non_buffered_filter;
+ u->input_filter_ctx = r;
+
if (!scf->upstream.request_buffering
&& scf->upstream.pass_request_body
&& !r->headers_in.chunked)
@@ -1145,6 +1150,37 @@ ngx_http_scgi_process_header(ngx_http_request_t *r)
}
+static ngx_int_t
+ngx_http_scgi_input_filter_init(void *data)
+{
+ ngx_http_request_t *r = data;
+ ngx_http_upstream_t *u;
+
+ u = r->upstream;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http scgi filter init s:%ui l:%O",
+ u->headers_in.status_n, u->headers_in.content_length_n);
+
+ if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
+ || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED)
+ {
+ u->pipe->length = 0;
+ u->length = 0;
+
+ } else if (r->method == NGX_HTTP_HEAD) {
+ u->pipe->length = -1;
+ u->length = -1;
+
+ } else {
+ u->pipe->length = u->headers_in.content_length_n;
+ u->length = u->headers_in.content_length_n;
+ }
+
+ return NGX_OK;
+}
+
+
static void
ngx_http_scgi_abort_request(ngx_http_request_t *r)
{
diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c
index 56dc236ef..fe15ee80d 100644
--- a/src/http/modules/ngx_http_uwsgi_module.c
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -67,6 +67,7 @@ static ngx_int_t ngx_http_uwsgi_create_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_uwsgi_reinit_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_uwsgi_process_status_line(ngx_http_request_t *r);
static ngx_int_t ngx_http_uwsgi_process_header(ngx_http_request_t *r);
+static ngx_int_t ngx_http_uwsgi_input_filter_init(void *data);
static void ngx_http_uwsgi_abort_request(ngx_http_request_t *r);
static void ngx_http_uwsgi_finalize_request(ngx_http_request_t *r,
ngx_int_t rc);
@@ -703,6 +704,10 @@ ngx_http_uwsgi_handler(ngx_http_request_t *r)
u->pipe->input_filter = ngx_event_pipe_copy_input_filter;
u->pipe->input_ctx = r;
+ u->input_filter_init = ngx_http_uwsgi_input_filter_init;
+ u->input_filter = ngx_http_upstream_non_buffered_filter;
+ u->input_filter_ctx = r;
+
if (!uwcf->upstream.request_buffering
&& uwcf->upstream.pass_request_body
&& !r->headers_in.chunked)
@@ -1141,6 +1146,7 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r)
r->upstream->request_bufs = cl;
}
+ b->flush = 1;
cl->next = NULL;
return NGX_OK;
@@ -1355,6 +1361,37 @@ ngx_http_uwsgi_process_header(ngx_http_request_t *r)
}
+static ngx_int_t
+ngx_http_uwsgi_input_filter_init(void *data)
+{
+ ngx_http_request_t *r = data;
+ ngx_http_upstream_t *u;
+
+ u = r->upstream;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http uwsgi filter init s:%ui l:%O",
+ u->headers_in.status_n, u->headers_in.content_length_n);
+
+ if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
+ || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED)
+ {
+ u->pipe->length = 0;
+ u->length = 0;
+
+ } else if (r->method == NGX_HTTP_HEAD) {
+ u->pipe->length = -1;
+ u->length = -1;
+
+ } else {
+ u->pipe->length = u->headers_in.content_length_n;
+ u->length = u->headers_in.content_length_n;
+ }
+
+ return NGX_OK;
+}
+
+
static void
ngx_http_uwsgi_abort_request(ngx_http_request_t *r)
{
diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c
index 0a645722c..7da64f906 100644
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -1493,14 +1493,14 @@ ngx_http_server_names(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
NGX_HASH_WILDCARD_KEY);
if (rc == NGX_ERROR) {
- return NGX_ERROR;
+ goto failed;
}
if (rc == NGX_DECLINED) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"invalid server name or wildcard \"%V\" on %V",
&name[n].name, &addr->opt.addr_text);
- return NGX_ERROR;
+ goto failed;
}
if (rc == NGX_BUSY) {
diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h
index f9e966409..cd0b4bbf8 100644
--- a/src/http/ngx_http_cache.h
+++ b/src/http/ngx_http_cache.h
@@ -160,6 +160,7 @@ struct ngx_http_file_cache_s {
ngx_path_t *path;
+ off_t min_free;
off_t max_size;
size_t bsize;
diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c
index ecdf11e28..e985f27b1 100644
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -1959,7 +1959,7 @@ ngx_http_file_cache_manager(void *data)
{
ngx_http_file_cache_t *cache = data;
- off_t size;
+ off_t size, free;
time_t wait;
ngx_msec_t elapsed, next;
ngx_uint_t count, watermark;
@@ -1988,7 +1988,19 @@ ngx_http_file_cache_manager(void *data)
size, count, (ngx_int_t) watermark);
if (size < cache->max_size && count < watermark) {
- break;
+
+ if (!cache->min_free) {
+ break;
+ }
+
+ free = ngx_fs_available(cache->path->name.data);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
+ "http file cache free: %O", free);
+
+ if (free > cache->min_free) {
+ break;
+ }
}
wait = ngx_http_file_cache_forced_expire(cache);
@@ -2304,7 +2316,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
char *confp = conf;
- off_t max_size;
+ off_t max_size, min_free;
u_char *last, *p;
time_t inactive;
ssize_t size;
@@ -2341,6 +2353,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
name.len = 0;
size = 0;
max_size = NGX_MAX_OFF_T_VALUE;
+ min_free = 0;
value = cf->args->elts;
@@ -2476,6 +2489,29 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
continue;
}
+ if (ngx_strncmp(value[i].data, "min_free=", 9) == 0) {
+
+#if (NGX_WIN32 || NGX_HAVE_STATFS || NGX_HAVE_STATVFS)
+
+ s.len = value[i].len - 9;
+ s.data = value[i].data + 9;
+
+ min_free = ngx_parse_offset(&s);
+ if (min_free < 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid min_free value \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+#else
+ ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+ "min_free is not supported "
+ "on this platform, ignored");
+#endif
+
+ continue;
+ }
+
if (ngx_strncmp(value[i].data, "loader_files=", 13) == 0) {
loader_files = ngx_atoi(value[i].data + 13, value[i].len - 13);
@@ -2607,6 +2643,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
cache->inactive = inactive;
cache->max_size = max_size;
+ cache->min_free = min_free;
caches = (ngx_array_t *) (confp + cmd->offset);
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index be96be47a..47f98ccb2 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -77,9 +77,6 @@ static void
static void
ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
ngx_uint_t do_write);
-static ngx_int_t ngx_http_upstream_non_buffered_filter_init(void *data);
-static ngx_int_t ngx_http_upstream_non_buffered_filter(void *data,
- ssize_t bytes);
#if (NGX_THREADS)
static ngx_int_t ngx_http_upstream_thread_handler(ngx_thread_task_t *task,
ngx_file_t *file);
@@ -1919,6 +1916,7 @@ ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u)
u->keepalive = 0;
u->upgrade = 0;
+ u->error = 0;
ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t));
u->headers_in.content_length_n = -1;
@@ -3627,7 +3625,7 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
return;
}
- if (upstream->read->error) {
+ if (upstream->read->error || u->error) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_BAD_GATEWAY);
return;
@@ -3705,14 +3703,14 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
}
-static ngx_int_t
+ngx_int_t
ngx_http_upstream_non_buffered_filter_init(void *data)
{
return NGX_OK;
}
-static ngx_int_t
+ngx_int_t
ngx_http_upstream_non_buffered_filter(void *data, ssize_t bytes)
{
ngx_http_request_t *r = data;
@@ -3748,6 +3746,18 @@ ngx_http_upstream_non_buffered_filter(void *data, ssize_t bytes)
return NGX_OK;
}
+ if (bytes > u->length) {
+
+ ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
+ "upstream sent more data than specified in "
+ "\"Content-Length\" header");
+
+ cl->buf->last = cl->buf->pos + u->length;
+ u->length = 0;
+
+ return NGX_OK;
+ }
+
u->length -= bytes;
return NGX_OK;
diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h
index 6079d7236..fd642c2d2 100644
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -391,6 +391,7 @@ struct ngx_http_upstream_s {
unsigned buffering:1;
unsigned keepalive:1;
unsigned upgrade:1;
+ unsigned error:1;
unsigned request_sent:1;
unsigned request_body_sent:1;
@@ -414,6 +415,8 @@ typedef struct {
ngx_int_t ngx_http_upstream_create(ngx_http_request_t *r);
void ngx_http_upstream_init(ngx_http_request_t *r);
+ngx_int_t ngx_http_upstream_non_buffered_filter_init(void *data);
+ngx_int_t ngx_http_upstream_non_buffered_filter(void *data, ssize_t bytes);
ngx_http_upstream_srv_conf_t *ngx_http_upstream_add(ngx_conf_t *cf,
ngx_url_t *u, ngx_uint_t flags);
char *ngx_http_upstream_bind_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
index 08d66c97b..ec553ecfe 100644
--- a/src/http/v2/ngx_http_v2.c
+++ b/src/http/v2/ngx_http_v2.c
@@ -60,6 +60,8 @@ typedef struct {
static void ngx_http_v2_read_handler(ngx_event_t *rev);
static void ngx_http_v2_write_handler(ngx_event_t *wev);
static void ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c);
+static void ngx_http_v2_lingering_close(ngx_http_v2_connection_t *h2c);
+static void ngx_http_v2_lingering_close_handler(ngx_event_t *rev);
static u_char *ngx_http_v2_state_proxy_protocol(ngx_http_v2_connection_t *h2c,
u_char *pos, u_char *end);
@@ -661,7 +663,7 @@ ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c)
}
if (h2c->goaway) {
- ngx_http_close_connection(c);
+ ngx_http_v2_lingering_close(h2c);
return;
}
@@ -699,6 +701,113 @@ ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c)
}
+static void
+ngx_http_v2_lingering_close(ngx_http_v2_connection_t *h2c)
+{
+ ngx_event_t *rev, *wev;
+ ngx_connection_t *c;
+ ngx_http_core_loc_conf_t *clcf;
+
+ c = h2c->connection;
+
+ clcf = ngx_http_get_module_loc_conf(h2c->http_connection->conf_ctx,
+ ngx_http_core_module);
+
+ if (clcf->lingering_close == NGX_HTTP_LINGERING_OFF) {
+ ngx_http_close_connection(c);
+ return;
+ }
+
+ rev = c->read;
+ rev->handler = ngx_http_v2_lingering_close_handler;
+
+ h2c->lingering_time = ngx_time() + (time_t) (clcf->lingering_time / 1000);
+ ngx_add_timer(rev, clcf->lingering_timeout);
+
+ if (ngx_handle_read_event(rev, 0) != NGX_OK) {
+ ngx_http_close_connection(c);
+ return;
+ }
+
+ wev = c->write;
+ wev->handler = ngx_http_empty_handler;
+
+ if (wev->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) {
+ if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) != NGX_OK) {
+ ngx_http_close_connection(c);
+ return;
+ }
+ }
+
+ if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) {
+ ngx_connection_error(c, ngx_socket_errno,
+ ngx_shutdown_socket_n " failed");
+ ngx_http_close_connection(c);
+ return;
+ }
+
+ if (rev->ready) {
+ ngx_http_v2_lingering_close_handler(rev);
+ }
+}
+
+
+static void
+ngx_http_v2_lingering_close_handler(ngx_event_t *rev)
+{
+ ssize_t n;
+ ngx_msec_t timer;
+ ngx_connection_t *c;
+ ngx_http_core_loc_conf_t *clcf;
+ ngx_http_v2_connection_t *h2c;
+ u_char buffer[NGX_HTTP_LINGERING_BUFFER_SIZE];
+
+ c = rev->data;
+ h2c = c->data;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
+ "http2 lingering close handler");
+
+ if (rev->timedout) {
+ ngx_http_close_connection(c);
+ return;
+ }
+
+ timer = (ngx_msec_t) h2c->lingering_time - (ngx_msec_t) ngx_time();
+ if ((ngx_msec_int_t) timer <= 0) {
+ ngx_http_close_connection(c);
+ return;
+ }
+
+ do {
+ n = c->recv(c, buffer, NGX_HTTP_LINGERING_BUFFER_SIZE);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "lingering read: %z", n);
+
+ if (n == NGX_ERROR || n == 0) {
+ ngx_http_close_connection(c);
+ return;
+ }
+
+ } while (rev->ready);
+
+ if (ngx_handle_read_event(rev, 0) != NGX_OK) {
+ ngx_http_close_connection(c);
+ return;
+ }
+
+ clcf = ngx_http_get_module_loc_conf(h2c->http_connection->conf_ctx,
+ ngx_http_core_module);
+ timer *= 1000;
+
+ if (timer > clcf->lingering_timeout) {
+ timer = clcf->lingering_timeout;
+ }
+
+ ngx_add_timer(rev, timer);
+}
+
+
static u_char *
ngx_http_v2_state_proxy_protocol(ngx_http_v2_connection_t *h2c, u_char *pos,
u_char *end)
@@ -4541,16 +4650,15 @@ ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c,
h2c->blocked = 1;
if (!c->error && !h2c->goaway) {
+ h2c->goaway = 1;
+
if (ngx_http_v2_send_goaway(h2c, status) != NGX_ERROR) {
(void) ngx_http_v2_send_output_queue(h2c);
}
}
- c->error = 1;
-
if (!h2c->processing && !h2c->pushing) {
- ngx_http_close_connection(c);
- return;
+ goto done;
}
c->read->handler = ngx_http_empty_handler;
@@ -4598,10 +4706,18 @@ ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c,
h2c->blocked = 0;
if (h2c->processing || h2c->pushing) {
+ c->error = 1;
+ return;
+ }
+
+done:
+
+ if (c->error) {
+ ngx_http_close_connection(c);
return;
}
- ngx_http_close_connection(c);
+ ngx_http_v2_lingering_close(h2c);
}
diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h
index 59ddf54e2..349229711 100644
--- a/src/http/v2/ngx_http_v2.h
+++ b/src/http/v2/ngx_http_v2.h
@@ -157,6 +157,8 @@ struct ngx_http_v2_connection_s {
ngx_uint_t last_sid;
ngx_uint_t last_push;
+ time_t lingering_time;
+
unsigned closed_nodes:8;
unsigned settings_ack:1;
unsigned table_update:1;
diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c
index 482d32763..1c82a8ead 100644
--- a/src/os/unix/ngx_files.c
+++ b/src/os/unix/ngx_files.c
@@ -875,9 +875,28 @@ ngx_fs_bsize(u_char *name)
return 512;
}
+#if (NGX_LINUX)
+ if ((size_t) fs.f_bsize > ngx_pagesize) {
+ return 512;
+ }
+#endif
+
return (size_t) fs.f_bsize;
}
+
+off_t
+ngx_fs_available(u_char *name)
+{
+ struct statfs fs;
+
+ if (statfs((char *) name, &fs) == -1) {
+ return NGX_MAX_OFF_T_VALUE;
+ }
+
+ return (off_t) fs.f_bavail * fs.f_bsize;
+}
+
#elif (NGX_HAVE_STATVFS)
size_t
@@ -893,9 +912,28 @@ ngx_fs_bsize(u_char *name)
return 512;
}
+#if (NGX_LINUX)
+ if ((size_t) fs.f_frsize > ngx_pagesize) {
+ return 512;
+ }
+#endif
+
return (size_t) fs.f_frsize;
}
+
+off_t
+ngx_fs_available(u_char *name)
+{
+ struct statvfs fs;
+
+ if (statvfs((char *) name, &fs) == -1) {
+ return NGX_MAX_OFF_T_VALUE;
+ }
+
+ return (off_t) fs.f_bavail * fs.f_frsize;
+}
+
#else
size_t
@@ -904,4 +942,11 @@ ngx_fs_bsize(u_char *name)
return 512;
}
+
+off_t
+ngx_fs_available(u_char *name)
+{
+ return NGX_MAX_OFF_T_VALUE;
+}
+
#endif
diff --git a/src/os/unix/ngx_files.h b/src/os/unix/ngx_files.h
index 383e38e65..d084713b6 100644
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -185,7 +185,10 @@ ngx_int_t ngx_set_file_time(u_char *name, ngx_fd_t fd, time_t s);
#define ngx_is_exec(sb) (((sb)->st_mode & S_IXUSR) == S_IXUSR)
#define ngx_file_access(sb) ((sb)->st_mode & 0777)
#define ngx_file_size(sb) (sb)->st_size
-#define ngx_file_fs_size(sb) ngx_max((sb)->st_size, (sb)->st_blocks * 512)
+#define ngx_file_fs_size(sb) \
+ (((sb)->st_blocks * 512 > (sb)->st_size \
+ && (sb)->st_blocks * 512 < (sb)->st_size + 8 * (sb)->st_blksize) \
+ ? (sb)->st_blocks * 512 : (sb)->st_size)
#define ngx_file_mtime(sb) (sb)->st_mtime
#define ngx_file_uniq(sb) (sb)->st_ino
@@ -346,6 +349,7 @@ ngx_int_t ngx_directio_off(ngx_fd_t fd);
#endif
size_t ngx_fs_bsize(u_char *name);
+off_t ngx_fs_available(u_char *name);
#if (NGX_HAVE_OPENAT)
diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c
index 5817a2c23..f87e00923 100644
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -77,12 +77,11 @@ ngx_master_process_cycle(ngx_cycle_t *cycle)
u_char *p;
size_t size;
ngx_int_t i;
- ngx_uint_t n, sigio;
+ ngx_uint_t sigio;
sigset_t set;
struct itimerval itv;
ngx_uint_t live;
ngx_msec_t delay;
- ngx_listening_t *ls;
ngx_core_conf_t *ccf;
sigemptyset(&set);
@@ -204,16 +203,7 @@ ngx_master_process_cycle(ngx_cycle_t *cycle)
if (ngx_quit) {
ngx_signal_worker_processes(cycle,
ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
-
- ls = cycle->listening.elts;
- for (n = 0; n < cycle->listening.nelts; n++) {
- if (ngx_close_socket(ls[n].fd) == -1) {
- ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
- ngx_close_socket_n " %V failed",
- &ls[n].addr_text);
- }
- }
- cycle->listening.nelts = 0;
+ ngx_close_listening_sockets(cycle);
continue;
}
diff --git a/src/os/unix/ngx_udp_sendmsg_chain.c b/src/os/unix/ngx_udp_sendmsg_chain.c
index 5399c7916..3d1d6dde4 100644
--- a/src/os/unix/ngx_udp_sendmsg_chain.c
+++ b/src/os/unix/ngx_udp_sendmsg_chain.c
@@ -189,6 +189,13 @@ ngx_udp_output_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *in, ngx_log_t *log)
return cl;
}
+ /* zero-sized datagram; pretend to have at least 1 iov */
+ if (n == 0) {
+ iov = &vec->iovs[n++];
+ iov->iov_base = NULL;
+ iov->iov_len = 0;
+ }
+
vec->count = n;
vec->size = total;
diff --git a/src/os/win32/ngx_files.c b/src/os/win32/ngx_files.c
index 0b131b58a..3017b45fe 100644
--- a/src/os/win32/ngx_files.c
+++ b/src/os/win32/ngx_files.c
@@ -658,6 +658,19 @@ ngx_fs_bsize(u_char *name)
}
+off_t
+ngx_fs_available(u_char *name)
+{
+ ULARGE_INTEGER navail;
+
+ if (GetDiskFreeSpaceEx((const char *) name, &navail, NULL, NULL) == 0) {
+ return NGX_MAX_OFF_T_VALUE;
+ }
+
+ return (off_t) navail.QuadPart;
+}
+
+
static ngx_int_t
ngx_win32_check_filename(u_char *name, u_short *u, size_t len)
{
diff --git a/src/os/win32/ngx_files.h b/src/os/win32/ngx_files.h
index 6eb720e78..a10839ba4 100644
--- a/src/os/win32/ngx_files.h
+++ b/src/os/win32/ngx_files.h
@@ -259,6 +259,7 @@ ngx_int_t ngx_directio_off(ngx_fd_t fd);
#define ngx_directio_off_n "ngx_directio_off_n"
size_t ngx_fs_bsize(u_char *name);
+off_t ngx_fs_available(u_char *name);
#define ngx_stdout GetStdHandle(STD_OUTPUT_HANDLE)
diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c
index 7484a728a..db11dd865 100644
--- a/src/stream/ngx_stream_proxy_module.c
+++ b/src/stream/ngx_stream_proxy_module.c
@@ -839,7 +839,7 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s)
u->upstream_buf.last = p;
}
- if (c->buffer && c->buffer->pos < c->buffer->last) {
+ if (c->buffer && c->buffer->pos <= c->buffer->last) {
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
"stream proxy add preread buffer: %uz",
c->buffer->last - c->buffer->pos);
@@ -853,6 +853,7 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s)
*cl->buf = *c->buffer;
cl->buf->tag = (ngx_buf_tag_t) &ngx_stream_proxy_module;
+ cl->buf->temporary = (cl->buf->pos == cl->buf->last) ? 0 : 1;
cl->buf->flush = 1;
cl->next = u->upstream_out;
diff --git a/src/stream/ngx_stream_write_filter_module.c b/src/stream/ngx_stream_write_filter_module.c
index 24326c60e..156a61c3d 100644
--- a/src/stream/ngx_stream_write_filter_module.c
+++ b/src/stream/ngx_stream_write_filter_module.c
@@ -234,7 +234,8 @@ ngx_stream_write_filter(ngx_stream_session_t *s, ngx_chain_t *in,
if (size == 0
&& !(c->buffered & NGX_LOWLEVEL_BUFFERED)
- && !(last && c->need_last_buf))
+ && !(last && c->need_last_buf)
+ && !(c->type == SOCK_DGRAM && flush))
{
if (last || flush || sync) {
for (cl = *out; cl; /* void */) {