Merge branch 'nginx' (nginx-1.11.13). Change-Id: I09f3e38baa909424d0c9ee898b8486cec97ea303 Signed-off-by: Piotr Sikora <piotrsikora@google.com>
diff --git a/.hgtags b/.hgtags index f56b37f..818243e 100644 --- a/.hgtags +++ b/.hgtags
@@ -411,3 +411,4 @@ 1ad0999a7ded3d4fb01c7acf8ff57c80b643da7e release-1.11.10 d8b321a876d6254e9e98795e3b194ef053290354 release-1.11.11 7f394e433f0003222aa6531931ecc0b24740d5e4 release-1.11.12 +3d0e8655f897959e48cc74e87670bb5492a58871 release-1.11.13
diff --git a/BUILD b/BUILD index ae282e2..55656bf 100644 --- a/BUILD +++ b/BUILD
@@ -1468,5 +1468,5 @@ preinst = "@nginx_pkgoss//:debian_preinst", prerm = "@nginx_pkgoss//:debian_prerm", section = "httpd", - version = "1.11.12", + version = "1.11.13", )
diff --git a/build.bzl b/build.bzl index 38e8c35..42b6b32 100644 --- a/build.bzl +++ b/build.bzl
@@ -663,7 +663,7 @@ name = "nginx_pkgoss", build_file_content = _PKGOSS_BUILD_FILE.format(nginx = nginx) + _PKGOSS_BUILD_FILE_TAIL, - commit = "6875999d1ccf62b0ecdc3cbad5f3b0a0c6f4069d", # nginx-1.11.12 + commit = "5ca52610ad80ed63446d4b833ffc4a7f9130d230", # nginx-1.11.13 remote = "https://nginx.googlesource.com/nginx-pkgoss", )
diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml index 6106043..ea39ab2 100644 --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml
@@ -5,6 +5,97 @@ <change_log title="nginx"> +<changes ver="1.11.13" date="2017-04-04"> + +<change type="feature"> +<para lang="ru"> +параметр http_429 в директивах proxy_next_upstream, fastcgi_next_upstream, +scgi_next_upstream и uwsgi_next_upstream.<br/> +Спасибо Piotr Sikora. +</para> +<para lang="en"> +the "http_429" parameter of the "proxy_next_upstream", "fastcgi_next_upstream", +"scgi_next_upstream", and "uwsgi_next_upstream" directives.<br/> +Thanks to Piotr Sikora. +</para> +</change> + +<change type="bugfix"> +<para lang="ru"> +в обработке ошибок выделения памяти. +</para> +<para lang="en"> +in memory allocation error handling. +</para> +</change> + +<change type="bugfix"> +<para lang="ru"> +при использовании директив sendfile и timer_resolution на Linux +запросы могли зависать. +</para> +<para lang="en"> +requests might hang +when using the "sendfile" and "timer_resolution" directives on Linux. +</para> +</change> + +<change type="bugfix"> +<para lang="ru"> +при использовании с подзапросами директив sendfile и aio_write +запросы могли зависать. +</para> +<para lang="en"> +requests might hang +when using the "sendfile" and "aio_write" directives with subrequests. +</para> +</change> + +<change type="bugfix"> +<para lang="ru"> +в модуле ngx_http_v2_module.<br/> +Спасибо Piotr Sikora. +</para> +<para lang="en"> +in the ngx_http_v2_module.<br/> +Thanks to Piotr Sikora. +</para> +</change> + +<change type="bugfix"> +<para lang="ru"> +при использовании HTTP/2 в рабочем процессе мог произойти segmentation fault. +</para> +<para lang="en"> +a segmentation fault might occur in a worker process when using HTTP/2. +</para> +</change> + +<change type="bugfix"> +<para lang="ru"> +запросы могли зависать +при использовании с подзапросами директив limit_rate, sendfile_max_chunk, +limit_req или метода $r->sleep() встроенного перла. +</para> +<para lang="en"> +requests might hang +when using the "limit_rate", "sendfile_max_chunk", "limit_req" directives, +or the $r->sleep() embedded perl method with subrequests. +</para> +</change> + +<change type="bugfix"> +<para lang="ru"> +в модуле ngx_http_slice_module. +</para> +<para lang="en"> +in the ngx_http_slice_module. +</para> +</change> + +</changes> + + <changes ver="1.11.12" date="2017-03-24"> <change type="bugfix">
diff --git a/src/core/nginx.h b/src/core/nginx.h index eb5bf53..12d96ee 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h
@@ -13,8 +13,8 @@ #define NGINX_NAME "nginx" #endif -#define nginx_version 1011012 -#define NGINX_VERSION "1.11.12" +#define nginx_version 1011013 +#define NGINX_VERSION "1.11.13" #define NGINX_VER NGINX_NAME "/" NGINX_VERSION #ifdef NGX_BUILD
diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c index 3dfdf2e..aee7a58 100644 --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c
@@ -115,16 +115,14 @@ n = old_cycle->paths.nelts ? old_cycle->paths.nelts : 10; - cycle->paths.elts = ngx_pcalloc(pool, n * sizeof(ngx_path_t *)); - if (cycle->paths.elts == NULL) { + if (ngx_array_init(&cycle->paths, pool, n, sizeof(ngx_path_t *)) + != NGX_OK) + { ngx_destroy_pool(pool); return NULL; } - cycle->paths.nelts = 0; - cycle->paths.size = sizeof(ngx_path_t *); - cycle->paths.nalloc = n; - cycle->paths.pool = pool; + ngx_memzero(cycle->paths.elts, n * sizeof(ngx_path_t *)); if (ngx_array_init(&cycle->config_dump, pool, 1, sizeof(ngx_conf_dump_t)) @@ -175,16 +173,14 @@ n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10; - cycle->listening.elts = ngx_pcalloc(pool, n * sizeof(ngx_listening_t)); - if (cycle->listening.elts == NULL) { + if (ngx_array_init(&cycle->listening, pool, n, sizeof(ngx_listening_t)) + != NGX_OK) + { ngx_destroy_pool(pool); return NULL; } - cycle->listening.nelts = 0; - cycle->listening.size = sizeof(ngx_listening_t); - cycle->listening.nalloc = n; - cycle->listening.pool = pool; + ngx_memzero(cycle->listening.elts, n * sizeof(ngx_listening_t)); ngx_queue_init(&cycle->reusable_connections_queue); @@ -768,15 +764,15 @@ } n = 10; - ngx_old_cycles.elts = ngx_pcalloc(ngx_temp_pool, - n * sizeof(ngx_cycle_t *)); - if (ngx_old_cycles.elts == NULL) { + + if (ngx_array_init(&ngx_old_cycles, ngx_temp_pool, n, + sizeof(ngx_cycle_t *)) + != NGX_OK) + { exit(1); } - ngx_old_cycles.nelts = 0; - ngx_old_cycles.size = sizeof(ngx_cycle_t *); - ngx_old_cycles.nalloc = n; - ngx_old_cycles.pool = ngx_temp_pool; + + ngx_memzero(ngx_old_cycles.elts, n * sizeof(ngx_cycle_t *)); ngx_cleaner_event.handler = ngx_clean_old_cycles; ngx_cleaner_event.log = cycle->log;
diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c index 71c4f17..8237fef 100644 --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c
@@ -500,8 +500,7 @@ #endif shm.size = size; - shm.name.len = sizeof("nginx_shared_zone") - 1; - shm.name.data = (u_char *) "nginx_shared_zone"; + ngx_str_set(&shm.name, "nginx_shared_zone"); shm.log = cycle->log; if (ngx_shm_alloc(&shm) != NGX_OK) {
diff --git a/src/http/modules/ngx_http_index_module.c b/src/http/modules/ngx_http_index_module.c index d3544db..c144b31 100644 --- a/src/http/modules/ngx_http_index_module.c +++ b/src/http/modules/ngx_http_index_module.c
@@ -217,13 +217,13 @@ if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, of.err, - "%s \"%s\" failed", of.failed, path.data); - if (of.err == 0) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, of.err, + "%s \"%s\" failed", of.failed, path.data); + #if (NGX_HAVE_OPENAT) if (of.err == NGX_EMLINK || of.err == NGX_ELOOP)
diff --git a/src/http/modules/ngx_http_limit_req_module.c b/src/http/modules/ngx_http_limit_req_module.c index ec3aadf..9e7def8 100644 --- a/src/http/modules/ngx_http_limit_req_module.c +++ b/src/http/modules/ngx_http_limit_req_module.c
@@ -276,6 +276,8 @@ r->read_event_handler = ngx_http_test_reading; r->write_event_handler = ngx_http_limit_req_delay; + + r->connection->write->delayed = 1; ngx_add_timer(r->connection->write, delay); return NGX_AGAIN; @@ -292,7 +294,7 @@ wev = r->connection->write; - if (!wev->timedout) { + if (wev->delayed) { if (ngx_handle_write_event(wev, 0) != NGX_OK) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); @@ -301,8 +303,6 @@ return; } - wev->timedout = 0; - if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return;
diff --git a/src/http/modules/ngx_http_log_module.c b/src/http/modules/ngx_http_log_module.c index 330dc7e..917ed55 100644 --- a/src/http/modules/ngx_http_log_module.c +++ b/src/http/modules/ngx_http_log_module.c
@@ -552,6 +552,11 @@ if (ngx_open_cached_file(llcf->open_file_cache, &log, &of, r->pool) != NGX_OK) { + if (of.err == 0) { + /* simulate successful logging */ + return len; + } + ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, "%s \"%s\" failed", of.failed, log.data); /* simulate successful logging */
diff --git a/src/http/modules/ngx_http_slice_filter_module.c b/src/http/modules/ngx_http_slice_filter_module.c index 2005939..7758342 100644 --- a/src/http/modules/ngx_http_slice_filter_module.c +++ b/src/http/modules/ngx_http_slice_filter_module.c
@@ -11,23 +11,25 @@ typedef struct { - size_t size; + size_t size; } ngx_http_slice_loc_conf_t; typedef struct { - off_t start; - off_t end; - ngx_str_t range; - ngx_str_t etag; - ngx_uint_t last; /* unsigned last:1; */ + off_t start; + off_t end; + ngx_str_t range; + ngx_str_t etag; + unsigned last:1; + unsigned active:1; + ngx_http_request_t *sr; } ngx_http_slice_ctx_t; typedef struct { - off_t start; - off_t end; - off_t complete_length; + off_t start; + off_t end; + off_t complete_length; } ngx_http_slice_content_range_t; @@ -169,6 +171,7 @@ } ctx->start = end; + ctx->active = 1; r->headers_out.status = NGX_HTTP_OK; r->headers_out.status_line.len = 0; @@ -209,7 +212,6 @@ { ngx_int_t rc; ngx_chain_t *cl; - ngx_http_request_t *sr; ngx_http_slice_ctx_t *ctx; ngx_http_slice_loc_conf_t *slcf; @@ -234,6 +236,16 @@ return rc; } + if (ctx->sr && !ctx->sr->done) { + return rc; + } + + if (!ctx->active) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "missing slice response"); + return NGX_ERROR; + } + if (ctx->start >= ctx->end) { ngx_http_set_ctx(r, NULL, ngx_http_slice_filter_module); ngx_http_send_special(r, NGX_HTTP_LAST); @@ -244,14 +256,14 @@ return rc; } - if (ngx_http_subrequest(r, &r->uri, &r->args, &sr, NULL, + if (ngx_http_subrequest(r, &r->uri, &r->args, &ctx->sr, NULL, NGX_HTTP_SUBREQUEST_CLONE) != NGX_OK) { return NGX_ERROR; } - ngx_http_set_ctx(sr, ctx, ngx_http_slice_filter_module); + ngx_http_set_ctx(ctx->sr, ctx, ngx_http_slice_filter_module); slcf = ngx_http_get_module_loc_conf(r, ngx_http_slice_filter_module); @@ -259,6 +271,8 @@ ctx->start + (off_t) slcf->size - 1) - ctx->range.data; + ctx->active = 0; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http slice subrequest: \"%V\"", &ctx->range);
diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs index 287d16e..865346a 100644 --- a/src/http/modules/perl/nginx.xs +++ b/src/http/modules/perl/nginx.xs
@@ -1001,6 +1001,7 @@ ctx->next = SvRV(ST(2)); + r->connection->write->delayed = 1; ngx_add_timer(r->connection->write, sleep); r->write_event_handler = ngx_http_perl_sleep_handler;
diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c index 2796319..6d3be91 100644 --- a/src/http/modules/perl/ngx_http_perl_module.c +++ b/src/http/modules/perl/ngx_http_perl_module.c
@@ -278,15 +278,16 @@ wev = r->connection->write; - if (wev->timedout) { - wev->timedout = 0; - ngx_http_perl_handle_request(r); + if (wev->delayed) { + + if (ngx_handle_write_event(wev, 0) != NGX_OK) { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + } + return; } - if (ngx_handle_write_event(wev, 0) != NGX_OK) { - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - } + ngx_http_perl_handle_request(r); }
diff --git a/src/http/ngx_http_copy_filter_module.c b/src/http/ngx_http_copy_filter_module.c index c696fb6..c8ad5da 100644 --- a/src/http/ngx_http_copy_filter_module.c +++ b/src/http/ngx_http_copy_filter_module.c
@@ -187,15 +187,24 @@ ngx_http_copy_aio_event_handler(ngx_event_t *ev) { ngx_event_aio_t *aio; + ngx_connection_t *c; ngx_http_request_t *r; aio = ev->data; r = aio->data; + c = r->connection; + + ngx_http_set_log_request(c->log, r); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http aio: \"%V?%V\"", &r->uri, &r->args); r->main->blocked--; r->aio = 0; - r->connection->write->handler(r->connection->write); + r->write_event_handler(r); + + ngx_http_run_posted_requests(c); } @@ -300,14 +309,33 @@ static void ngx_http_copy_thread_event_handler(ngx_event_t *ev) { + ngx_connection_t *c; ngx_http_request_t *r; r = ev->data; + c = r->connection; + + ngx_http_set_log_request(c->log, r); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http thread: \"%V?%V\"", &r->uri, &r->args); r->main->blocked--; r->aio = 0; - r->connection->write->handler(r->connection->write); + if (r->done) { + /* + * trigger connection event handler if the subrequest was + * already finalized; this can happen if the handler is used + * for sendfile() in threads + */ + + c->write->handler(c->write); + + } else { + r->write_event_handler(r); + ngx_http_run_posted_requests(c); + } } #endif
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 9ab2e1f..734e1d8 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c
@@ -1314,6 +1314,11 @@ if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { + if (of.err == 0) { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_OK; + } + if (of.err != NGX_ENOENT && of.err != NGX_ENOTDIR && of.err != NGX_ENAMETOOLONG)
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index a9a9206..9ede5c6 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c
@@ -2285,6 +2285,11 @@ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "http run request: \"%V?%V\"", &r->uri, &r->args); + if (ev->delayed && ev->timedout) { + ev->delayed = 0; + ev->timedout = 0; + } + if (ev->write) { r->write_event_handler(r); @@ -2694,7 +2699,7 @@ static void ngx_http_writer(ngx_http_request_t *r) { - int rc; + ngx_int_t rc; ngx_event_t *wev; ngx_connection_t *c; ngx_http_core_loc_conf_t *clcf; @@ -2708,34 +2713,22 @@ clcf = ngx_http_get_module_loc_conf(r->main, ngx_http_core_module); if (wev->timedout) { - if (!wev->delayed) { - ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, - "client timed out"); - c->timedout = 1; + ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, + "client timed out"); + c->timedout = 1; - ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT); - return; - } - - wev->timedout = 0; - wev->delayed = 0; - - if (!wev->ready) { - ngx_add_timer(wev, clcf->send_timeout); - - if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) { - ngx_http_close_request(r, 0); - } - - return; - } - + ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT); + return; } if (wev->delayed || r->aio) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0, "http writer delayed"); + if (!wev->delayed) { + ngx_add_timer(wev, clcf->send_timeout); + } + if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) { ngx_http_close_request(r, 0); } @@ -2746,7 +2739,7 @@ rc = ngx_http_output_filter(r, NULL); ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http writer output filter: %d, \"%V?%V\"", + "http writer output filter: %i, \"%V?%V\"", rc, &r->uri, &r->args); if (rc == NGX_ERROR) {
diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c index cc4d679..96f3ec6 100644 --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c
@@ -1513,6 +1513,12 @@ if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { + if (of.err == 0) { + e->ip = ngx_http_script_exit; + e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; + return; + } + if (of.err != NGX_ENOENT && of.err != NGX_ENOTDIR && of.err != NGX_ENAMETOOLONG)
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index d04dbbb..9e1f3b0 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c
@@ -1247,6 +1247,11 @@ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "http upstream request: \"%V?%V\"", &r->uri, &r->args); + if (ev->delayed && ev->timedout) { + ev->delayed = 0; + ev->timedout = 0; + } + if (ev->write) { u->write_event_handler(r, u); @@ -3805,9 +3810,19 @@ r->main->blocked--; r->aio = 0; - r->write_event_handler(r); + if (r->done) { + /* + * trigger connection event handler if the subrequest was + * already finalized; this can happen if the handler is used + * for sendfile() in threads + */ - ngx_http_run_posted_requests(c); + c->write->handler(c->write); + + } else { + r->write_event_handler(r); + ngx_http_run_posted_requests(c); + } } #endif @@ -3855,31 +3870,9 @@ if (wev->timedout) { - if (wev->delayed) { - - wev->timedout = 0; - wev->delayed = 0; - - if (!wev->ready) { - ngx_add_timer(wev, p->send_timeout); - - if (ngx_handle_write_event(wev, p->send_lowat) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, NGX_ERROR); - } - - return; - } - - if (ngx_event_pipe(p, wev->write) == NGX_ABORT) { - ngx_http_upstream_finalize_request(r, u, NGX_ERROR); - return; - } - - } else { - p->downstream_error = 1; - c->timedout = 1; - ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out"); - } + p->downstream_error = 1; + c->timedout = 1; + ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out"); } else { @@ -3924,30 +3917,8 @@ if (rev->timedout) { - if (rev->delayed) { - - rev->timedout = 0; - rev->delayed = 0; - - if (!rev->ready) { - ngx_add_timer(rev, p->read_timeout); - - if (ngx_handle_read_event(rev, 0) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, NGX_ERROR); - } - - return; - } - - if (ngx_event_pipe(p, 0) == NGX_ABORT) { - ngx_http_upstream_finalize_request(r, u, NGX_ERROR); - return; - } - - } else { - p->upstream_error = 1; - ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out"); - } + p->upstream_error = 1; + ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out"); } else { @@ -4184,8 +4155,7 @@ if (u->peer.sockaddr) { if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_403 - || ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404 - || ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_429) + || ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404) { state = NGX_PEER_NEXT;
diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 34f0dac..4910ad8 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c
@@ -817,7 +817,7 @@ NGX_HTTP_V2_PROTOCOL_ERROR); } - h2c->state.length -= h2c->state.padding + 1; + h2c->state.length -= 1 + h2c->state.padding; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, @@ -942,7 +942,7 @@ if (size >= h2c->state.length) { size = h2c->state.length; - stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG; + stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG; } r = stream->request; @@ -1910,7 +1910,7 @@ if (node == NULL || node->stream == NULL) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "unknown http2 stream"); + "unknown http2 stream"); return ngx_http_v2_state_complete(h2c, pos, end); } @@ -2048,6 +2048,7 @@ break; case NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING: + if (value > NGX_HTTP_V2_MAX_FRAME_SIZE || value < NGX_HTTP_V2_DEFAULT_FRAME_SIZE) { @@ -3133,7 +3134,7 @@ } ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent unknown pseudo header \"%V\"", + "client sent unknown pseudo-header \":%V\"", &header->name); return NGX_DECLINED; @@ -3280,14 +3281,14 @@ { if (r->schema_start) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent duplicate :schema header"); + "client sent duplicate :scheme header"); return NGX_DECLINED; } if (header->value.len == 0) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent empty :schema header"); + "client sent empty :scheme header"); return NGX_DECLINED; } @@ -4194,6 +4195,14 @@ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http2 handle connection handler"); + c = rev->data; + h2c = c->data; + + if (c->error) { + ngx_http_v2_finalize_connection(h2c, 0); + return; + } + rev->handler = ngx_http_v2_read_handler; if (rev->ready) { @@ -4201,9 +4210,6 @@ return; } - c = rev->data; - h2c = c->data; - if (h2c->last_out && ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) { ngx_http_v2_finalize_connection(h2c, 0); return; @@ -4326,7 +4332,10 @@ if (stream->queued) { stream->queued = 0; + ev = fc->write; + ev->active = 0; + ev->ready = 1; } else { ev = fc->read;
diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h index cddfccd..7d2a2ea 100644 --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h
@@ -249,8 +249,8 @@ { ngx_http_v2_out_frame_t **out; - for (out = &h2c->last_out; *out; out = &(*out)->next) - { + for (out = &h2c->last_out; *out; out = &(*out)->next) { + if ((*out)->blocked || (*out)->stream == NULL) { break; }
diff --git a/src/os/unix/ngx_linux_sendfile_chain.c b/src/os/unix/ngx_linux_sendfile_chain.c index 3c0696a..b44724c 100644 --- a/src/os/unix/ngx_linux_sendfile_chain.c +++ b/src/os/unix/ngx_linux_sendfile_chain.c
@@ -20,8 +20,8 @@ #error sendfile64() is required! #endif -static ngx_int_t ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file, - size_t size, size_t *sent); +static ssize_t ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file, + size_t size); static void ngx_linux_sendfile_thread_handler(void *data, ngx_log_t *log); #endif @@ -56,10 +56,6 @@ ngx_chain_t *cl; ngx_iovec_t header; struct iovec headers[NGX_IOVS_PREALLOCATE]; -#if (NGX_THREADS) - ngx_int_t rc; - ngx_uint_t thread_handled, thread_complete; -#endif wev = c->write; @@ -82,10 +78,6 @@ for ( ;; ) { prev_send = send; -#if (NGX_THREADS) - thread_handled = 0; - thread_complete = 0; -#endif /* create the iovec and coalesce the neighbouring bufs */ @@ -179,38 +171,19 @@ } #endif -#if (NGX_THREADS) - if (file->file->thread_handler) { - rc = ngx_linux_sendfile_thread(c, file, file_size, &sent); + n = ngx_linux_sendfile(c, file, file_size); - switch (rc) { - case NGX_OK: - thread_handled = 1; - break; - - case NGX_DONE: - thread_complete = 1; - break; - - case NGX_AGAIN: - break; - - default: /* NGX_ERROR */ - return NGX_CHAIN_ERROR; - } - - } else -#endif - { - n = ngx_linux_sendfile(c, file, file_size); - - if (n == NGX_ERROR) { - return NGX_CHAIN_ERROR; - } - - sent = (n == NGX_AGAIN) ? 0 : n; + if (n == NGX_ERROR) { + return NGX_CHAIN_ERROR; } + if (n == NGX_DONE) { + /* thread task posted */ + return in; + } + + sent = (n == NGX_AGAIN) ? 0 : n; + } else { n = ngx_writev(c, &header); @@ -225,21 +198,27 @@ in = ngx_chain_update_sent(in, sent); - if ((size_t) (send - prev_send) != sent) { -#if (NGX_THREADS) - if (thread_handled) { - return in; - } - - if (thread_complete) { - send = prev_send + sent; - continue; - } -#endif + if (n == NGX_AGAIN) { wev->ready = 0; return in; } + if ((size_t) (send - prev_send) != sent) { + + /* + * sendfile() on Linux 4.3+ might be interrupted at any time, + * and provides no indication if it was interrupted or not, + * so we have to retry till an explicit EAGAIN + * + * sendfile() in threads can also report less bytes written + * than we are prepared to send now, since it was started in + * some point in the past, so we again have to retry + */ + + send = prev_send + sent; + continue; + } + if (send >= limit || in == NULL) { return in; } @@ -258,6 +237,14 @@ ssize_t n; ngx_err_t err; +#if (NGX_THREADS) + + if (file->file->thread_handler) { + return ngx_linux_sendfile_thread(c, file, size); + } + +#endif + #if (NGX_HAVE_SENDFILE64) offset = file->file_pos; #else @@ -324,9 +311,8 @@ } ngx_linux_sendfile_ctx_t; -static ngx_int_t -ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file, size_t size, - size_t *sent) +static ssize_t +ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file, size_t size) { ngx_event_t *wev; ngx_thread_task_t *task; @@ -356,10 +342,14 @@ task->event.complete = 0; if (ctx->err == NGX_EAGAIN) { - *sent = 0; + /* + * if wev->complete is set, this means that a write event + * happened while we were waiting for the thread task, so + * we have to retry sending even on EAGAIN + */ if (wev->complete) { - return NGX_DONE; + return 0; } return NGX_AGAIN; @@ -384,13 +374,7 @@ return NGX_ERROR; } - *sent = ctx->sent; - - if (ctx->sent == ctx->size || wev->complete) { - return NGX_DONE; - } - - return NGX_AGAIN; + return ctx->sent; } if (task->event.active && ctx->file == file) { @@ -399,9 +383,7 @@ * or multiple calls of the next body filter from a filter */ - *sent = 0; - - return NGX_OK; + return NGX_DONE; } ctx->file = file; @@ -414,9 +396,7 @@ return NGX_ERROR; } - *sent = 0; - - return NGX_OK; + return NGX_DONE; }
diff --git a/src/stream/ngx_stream_log_module.c b/src/stream/ngx_stream_log_module.c index 6b29340..466bdda 100644 --- a/src/stream/ngx_stream_log_module.c +++ b/src/stream/ngx_stream_log_module.c
@@ -443,6 +443,11 @@ s->connection->pool) != NGX_OK) { + if (of.err == 0) { + /* simulate successful logging */ + return len; + } + ngx_log_error(NGX_LOG_CRIT, s->connection->log, ngx_errno, "%s \"%s\" failed", of.failed, log.data); /* simulate successful logging */