From adbd28b7a9843ebce895f9903f19c5a740d61db4 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Fri, 10 Sep 2021 12:59:22 +0300 Subject: Request body: do not create temp file if there's nothing to write. Do this only when the entire request body is empty and r->request_body_in_file_only is set. The issue manifested itself with missing warning "a client request body is buffered to a temporary file" when the entire rb->buf is full and all buffers are delayed by a filter. --- src/http/ngx_http_request_body.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/http') diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c index 89a4c7492..ad3549f98 100644 --- a/src/http/ngx_http_request_body.c +++ b/src/http/ngx_http_request_body.c @@ -1309,7 +1309,7 @@ ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) if (rb->rest > 0) { - if (rb->buf && rb->buf->last == rb->buf->end + if (rb->bufs && rb->buf && rb->buf->last == rb->buf->end && ngx_http_write_request_body(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; -- cgit From c9c3f2f005c43fd885bd78f86e1044261e639bea Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Wed, 6 Oct 2021 18:01:42 +0300 Subject: Fixed $content_length cacheability with chunked (ticket #2252). --- src/http/ngx_http_variables.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/http') diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c index c25d80ccf..942dacd70 100644 --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -1179,6 +1179,10 @@ ngx_http_variable_content_length(ngx_http_request_t *r, v->no_cacheable = 0; v->not_found = 0; + } else if (r->headers_in.chunked) { + v->not_found = 1; + v->no_cacheable = 1; + } else { v->not_found = 1; } -- cgit From 2a88047ac1a88fbe6038a822e0f1b67af847c998 Mon Sep 17 00:00:00 2001 From: Awdhesh Mathpal Date: Thu, 7 Oct 2021 19:23:11 -0700 Subject: Proxy: disabled keepalive on extra data in non-buffered mode. The u->keepalive flag is initialized early if the response has no body (or an empty body), and needs to be reset if there are any extra data, similarly to how it is done in ngx_http_proxy_copy_filter(). Missed in 83c4622053b0. --- src/http/modules/ngx_http_proxy_module.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/http') diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 084462746..a5cc27b1e 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -2337,6 +2337,7 @@ ngx_http_proxy_non_buffered_copy_filter(void *data, ssize_t bytes) ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "upstream sent more data than specified in " "\"Content-Length\" header"); + u->keepalive = 0; return NGX_OK; } -- cgit From 6119609cae6591320e5fc4b7d8e4546f59d40632 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 12 Oct 2021 23:18:18 +0300 Subject: Synced ngx_http_subrequest() argument names (ticket #2255). --- src/http/ngx_http_core_module.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/http') diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index 002d4193a..004a98eef 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -502,8 +502,8 @@ ngx_int_t ngx_http_gzip_ok(ngx_http_request_t *r); ngx_int_t ngx_http_subrequest(ngx_http_request_t *r, - ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **sr, - ngx_http_post_subrequest_t *psr, ngx_uint_t flags); + ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **psr, + ngx_http_post_subrequest_t *ps, ngx_uint_t flags); ngx_int_t ngx_http_internal_redirect(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args); ngx_int_t ngx_http_named_location(ngx_http_request_t *r, ngx_str_t *name); -- cgit From dde319ee0c9de26a6f104feb062cfffaa32c16c0 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 18 Oct 2021 16:46:59 +0300 Subject: Upstream: fixed logging level of upstream invalid header errors. In b87b7092cedb (nginx 1.21.1), logging level of "upstream sent invalid header" errors was accidentally changed to "info". This change restores the "error" level, which is a proper logging level for upstream-side errors. --- src/http/modules/ngx_http_fastcgi_module.c | 2 +- src/http/modules/ngx_http_proxy_module.c | 2 +- src/http/modules/ngx_http_scgi_module.c | 2 +- src/http/modules/ngx_http_uwsgi_module.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/http') diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index 69ac0f72c..4a8dc338e 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -2021,7 +2021,7 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + ngx_log_error(NGX_LOG_ERR, 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); diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index a5cc27b1e..7c4061c02 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -2021,7 +2021,7 @@ ngx_http_proxy_process_header(ngx_http_request_t *r) /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + ngx_log_error(NGX_LOG_ERR, 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); diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c index 570713df9..e5d31ae91 100644 --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -1142,7 +1142,7 @@ ngx_http_scgi_process_header(ngx_http_request_t *r) /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + ngx_log_error(NGX_LOG_ERR, 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); diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c index 4f9c349c2..d46741a00 100644 --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -1363,7 +1363,7 @@ ngx_http_uwsgi_process_header(ngx_http_request_t *r) /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + ngx_log_error(NGX_LOG_ERR, 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); -- cgit From 1db517fb71aed6d6fffc8347086f89eb29b83dea Mon Sep 17 00:00:00 2001 From: Vladimir Homutov Date: Fri, 15 Oct 2021 10:02:15 +0300 Subject: HTTP/2: removed support for NPN. NPN was replaced with ALPN, published as RFC 7301 in July 2014. It used to negotiate SPDY (and, in transition, HTTP/2). NPN supported appeared in OpenSSL 1.0.1. It does not work with TLSv1.3 [1]. ALPN is supported since OpenSSL 1.0.2. The NPN support was dropped in Firefox 53 [2] and Chrome 51 [3]. [1] https://github.com/openssl/openssl/issues/3665. [2] https://bugzilla.mozilla.org/show_bug.cgi?id=1248198 [3] https://www.chromestatus.com/feature/5767920709795840 --- src/http/modules/ngx_http_ssl_module.c | 59 +++------------------------------- src/http/ngx_http.c | 5 ++- src/http/ngx_http_request.c | 14 +------- src/http/v2/ngx_http_v2.h | 3 +- 4 files changed, 9 insertions(+), 72 deletions(-) (limited to 'src/http') diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index 1a744fff1..ed399f0cd 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -17,7 +17,7 @@ typedef ngx_int_t (*ngx_ssl_variable_handler_pt)(ngx_connection_t *c, #define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5" #define NGX_DEFAULT_ECDH_CURVE "auto" -#define NGX_HTTP_NPN_ADVERTISE "\x08http/1.1" +#define NGX_HTTP_ALPN_PROTO "\x08http/1.1" #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation @@ -26,11 +26,6 @@ static int ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char *in, unsigned int inlen, void *arg); #endif -#ifdef TLSEXT_TYPE_next_proto_neg -static int ngx_http_ssl_npn_advertised(ngx_ssl_conn_t *ssl_conn, - const unsigned char **out, unsigned int *outlen, void *arg); -#endif - static ngx_int_t ngx_http_ssl_static_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_ssl_variable(ngx_http_request_t *r, @@ -444,15 +439,14 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out, hc = c->data; if (hc->addr_conf->http2) { - srv = - (unsigned char *) NGX_HTTP_V2_ALPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE; - srvlen = sizeof(NGX_HTTP_V2_ALPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE) - 1; + srv = (unsigned char *) NGX_HTTP_V2_ALPN_PROTO NGX_HTTP_ALPN_PROTO; + srvlen = sizeof(NGX_HTTP_V2_ALPN_PROTO NGX_HTTP_ALPN_PROTO) - 1; } else #endif { - srv = (unsigned char *) NGX_HTTP_NPN_ADVERTISE; - srvlen = sizeof(NGX_HTTP_NPN_ADVERTISE) - 1; + srv = (unsigned char *) NGX_HTTP_ALPN_PROTO; + srvlen = sizeof(NGX_HTTP_ALPN_PROTO) - 1; } if (SSL_select_next_proto((unsigned char **) out, outlen, srv, srvlen, @@ -471,44 +465,6 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out, #endif -#ifdef TLSEXT_TYPE_next_proto_neg - -static int -ngx_http_ssl_npn_advertised(ngx_ssl_conn_t *ssl_conn, - const unsigned char **out, unsigned int *outlen, void *arg) -{ -#if (NGX_HTTP_V2 || NGX_DEBUG) - ngx_connection_t *c; - - c = ngx_ssl_get_connection(ssl_conn); - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "SSL NPN advertised"); -#endif - -#if (NGX_HTTP_V2) - { - ngx_http_connection_t *hc; - - hc = c->data; - - if (hc->addr_conf->http2) { - *out = - (unsigned char *) NGX_HTTP_V2_NPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE; - *outlen = sizeof(NGX_HTTP_V2_NPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE) - 1; - - return SSL_TLSEXT_ERR_OK; - } - } -#endif - - *out = (unsigned char *) NGX_HTTP_NPN_ADVERTISE; - *outlen = sizeof(NGX_HTTP_NPN_ADVERTISE) - 1; - - return SSL_TLSEXT_ERR_OK; -} - -#endif - - static ngx_int_t ngx_http_ssl_static_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) @@ -792,11 +748,6 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) SSL_CTX_set_alpn_select_cb(conf->ssl.ctx, ngx_http_ssl_alpn_select, NULL); #endif -#ifdef TLSEXT_TYPE_next_proto_neg - SSL_CTX_set_next_protos_advertised_cb(conf->ssl.ctx, - ngx_http_ssl_npn_advertised, NULL); -#endif - if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, conf->prefer_server_ciphers) != NGX_OK) diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index 3d5c4ac16..73c08d593 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -1338,13 +1338,12 @@ ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, } #if (NGX_HTTP_V2 && NGX_HTTP_SSL \ - && !defined TLSEXT_TYPE_application_layer_protocol_negotiation \ - && !defined TLSEXT_TYPE_next_proto_neg) + && !defined TLSEXT_TYPE_application_layer_protocol_negotiation) if (lsopt->http2 && lsopt->ssl) { ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "nginx was built with OpenSSL that lacks ALPN " - "and NPN support, HTTP/2 is not enabled for %V", + "support, HTTP/2 is not enabled for %V", &lsopt->addr_text); } diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index bf931bf35..76bbcd67c 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -806,8 +806,7 @@ ngx_http_ssl_handshake_handler(ngx_connection_t *c) c->ssl->no_wait_shutdown = 1; #if (NGX_HTTP_V2 \ - && (defined TLSEXT_TYPE_application_layer_protocol_negotiation \ - || defined TLSEXT_TYPE_next_proto_neg)) + && defined TLSEXT_TYPE_application_layer_protocol_negotiation) { unsigned int len; const unsigned char *data; @@ -817,19 +816,8 @@ ngx_http_ssl_handshake_handler(ngx_connection_t *c) if (hc->addr_conf->http2) { -#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation SSL_get0_alpn_selected(c->ssl->connection, &data, &len); -#ifdef TLSEXT_TYPE_next_proto_neg - if (len == 0) { - SSL_get0_next_proto_negotiated(c->ssl->connection, &data, &len); - } -#endif - -#else /* TLSEXT_TYPE_next_proto_neg */ - SSL_get0_next_proto_negotiated(c->ssl->connection, &data, &len); -#endif - if (len == 2 && data[0] == 'h' && data[1] == '2') { ngx_http_v2_init(c->read); return; diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h index 349229711..0eceae3d5 100644 --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -13,8 +13,7 @@ #include -#define NGX_HTTP_V2_ALPN_ADVERTISE "\x02h2" -#define NGX_HTTP_V2_NPN_ADVERTISE NGX_HTTP_V2_ALPN_ADVERTISE +#define NGX_HTTP_V2_ALPN_PROTO "\x02h2" #define NGX_HTTP_V2_STATE_BUFFER_SIZE 16 -- cgit From a9f4f25b72c39653795dfb4b1f13b55625fb9fbc Mon Sep 17 00:00:00 2001 From: Vladimir Homutov Date: Thu, 14 Oct 2021 11:46:23 +0300 Subject: SSL: added $ssl_alpn_protocol variable. The variable contains protocol selected by ALPN during handshake and is empty otherwise. --- src/http/modules/ngx_http_ssl_module.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/http') diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index ed399f0cd..87f038898 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -358,6 +358,9 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { { ngx_string("ssl_server_name"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_server_name, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_alpn_protocol"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_alpn_protocol, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_client_cert"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_certificate, NGX_HTTP_VAR_CHANGEABLE, 0 }, -- cgit From ebb6f7d6563f51ae8325e3c0f10e9c5a91004fda Mon Sep 17 00:00:00 2001 From: Vladimir Homutov Date: Wed, 20 Oct 2021 09:50:02 +0300 Subject: HTTP: connections with wrong ALPN protocols are now rejected. This is a recommended behavior by RFC 7301 and is useful for mitigation of protocol confusion attacks [1]. To avoid possible negative effects, list of supported protocols was extended to include all possible HTTP protocol ALPN IDs registered by IANA [2], i.e. "http/1.0" and "http/0.9". [1] https://alpaca-attack.com/ [2] https://www.iana.org/assignments/tls-extensiontype-values/ --- src/http/modules/ngx_http_ssl_module.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'src/http') diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index 87f038898..c633f3464 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -17,7 +17,7 @@ typedef ngx_int_t (*ngx_ssl_variable_handler_pt)(ngx_connection_t *c, #define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5" #define NGX_DEFAULT_ECDH_CURVE "auto" -#define NGX_HTTP_ALPN_PROTO "\x08http/1.1" +#define NGX_HTTP_ALPN_PROTOS "\x08http/1.1\x08http/1.0\x08http/0.9" #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation @@ -442,21 +442,20 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out, hc = c->data; if (hc->addr_conf->http2) { - srv = (unsigned char *) NGX_HTTP_V2_ALPN_PROTO NGX_HTTP_ALPN_PROTO; - srvlen = sizeof(NGX_HTTP_V2_ALPN_PROTO NGX_HTTP_ALPN_PROTO) - 1; - + srv = (unsigned char *) NGX_HTTP_V2_ALPN_PROTO NGX_HTTP_ALPN_PROTOS; + srvlen = sizeof(NGX_HTTP_V2_ALPN_PROTO NGX_HTTP_ALPN_PROTOS) - 1; } else #endif { - srv = (unsigned char *) NGX_HTTP_ALPN_PROTO; - srvlen = sizeof(NGX_HTTP_ALPN_PROTO) - 1; + srv = (unsigned char *) NGX_HTTP_ALPN_PROTOS; + srvlen = sizeof(NGX_HTTP_ALPN_PROTOS) - 1; } if (SSL_select_next_proto((unsigned char **) out, outlen, srv, srvlen, in, inlen) != OPENSSL_NPN_NEGOTIATED) { - return SSL_TLSEXT_ERR_NOACK; + return SSL_TLSEXT_ERR_ALERT_FATAL; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, -- cgit From 1fc61b7b1ff182e86078200a59d3c523419c7b3b Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 21 Oct 2021 18:44:07 +0300 Subject: SSL: SSL_sendfile() support with kernel TLS. Requires OpenSSL 3.0 compiled with "enable-ktls" option. Further, KTLS needs to be enabled in kernel, and in OpenSSL, either via OpenSSL configuration file or with "ssl_conf_command Options KTLS;" in nginx configuration. On FreeBSD, kernel TLS is available starting with FreeBSD 13.0, and can be enabled with "sysctl kern.ipc.tls.enable=1" and "kldload ktls_ocf" to load a software backend, see man ktls(4) for details. On Linux, kernel TLS is available starting with kernel 4.13 (at least 5.2 is recommended), and needs kernel compiled with CONFIG_TLS=y (with CONFIG_TLS=m, which is used at least on Ubuntu 21.04 by default, the tls module needs to be loaded with "modprobe tls"). --- src/http/ngx_http_request.c | 2 +- src/http/ngx_http_upstream.c | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'src/http') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 76bbcd67c..013b7158e 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -607,7 +607,7 @@ ngx_http_alloc_request(ngx_connection_t *c) } #if (NGX_HTTP_SSL) - if (c->ssl) { + if (c->ssl && !c->ssl->sendfile) { r->main_filter_need_in_memory = 1; } #endif diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 01c7877e6..daa8d2201 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -1683,9 +1683,6 @@ ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r, return; } - c->sendfile = 0; - u->output.sendfile = 0; - if (u->conf->ssl_server_name || u->conf->ssl_verify) { if (ngx_http_upstream_ssl_name(r, u, c) != NGX_OK) { ngx_http_upstream_finalize_request(r, u, @@ -1791,6 +1788,11 @@ ngx_http_upstream_ssl_handshake(ngx_http_request_t *r, ngx_http_upstream_t *u, } } + if (!c->ssl->sendfile) { + c->sendfile = 0; + u->output.sendfile = 0; + } + c->write->handler = ngx_http_upstream_handler; c->read->handler = ngx_http_upstream_handler; -- cgit From 27cdfe30f7505361c31e4d3b2d0d21adaae803c4 Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Thu, 28 Oct 2021 13:11:31 +0300 Subject: Mp4: added ngx_http_mp4_update_mdhd_atom() function. The function updates the duration field of mdhd atom. Previously it was updated in ngx_http_mp4_read_mdhd_atom(). The change makes it possible to alter track duration as a result of processing track frames. --- src/http/modules/ngx_http_mp4_module.c | 40 +++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 8 deletions(-) (limited to 'src/http') diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c index 0e93fbd09..fab8e2ca2 100644 --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -70,6 +70,7 @@ typedef struct { ngx_uint_t end_chunk_samples; uint64_t start_chunk_samples_size; uint64_t end_chunk_samples_size; + uint64_t duration; off_t start_offset; off_t end_offset; @@ -253,6 +254,8 @@ static void ngx_http_mp4_update_mdia_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak); static ngx_int_t ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); +static void ngx_http_mp4_update_mdhd_atom(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak); static ngx_int_t ngx_http_mp4_read_hdlr_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); static ngx_int_t ngx_http_mp4_read_minf_atom(ngx_http_mp4_file_t *mp4, @@ -822,7 +825,7 @@ ngx_http_mp4_process(ngx_http_mp4_file_t *mp4) ngx_http_mp4_update_stbl_atom(mp4, &trak[i]); ngx_http_mp4_update_minf_atom(mp4, &trak[i]); - trak[i].size += trak[i].mdhd_size; + ngx_http_mp4_update_mdhd_atom(mp4, &trak[i]); trak[i].size += trak[i].hdlr_size; ngx_http_mp4_update_mdia_atom(mp4, &trak[i]); trak[i].size += trak[i].tkhd_size; @@ -1749,16 +1752,10 @@ ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) trak = ngx_mp4_last_trak(mp4); trak->mdhd_size = atom_size; trak->timescale = timescale; + trak->duration = duration; ngx_mp4_set_32value(mdhd_atom->size, atom_size); - if (mdhd_atom->version[0] == 0) { - ngx_mp4_set_32value(mdhd_atom->duration, duration); - - } else { - ngx_mp4_set_64value(mdhd64_atom->duration, duration); - } - atom = &trak->mdhd_atom_buf; atom->temporary = 1; atom->pos = atom_header; @@ -1772,6 +1769,33 @@ ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) } +static void +ngx_http_mp4_update_mdhd_atom(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak) +{ + ngx_buf_t *atom; + ngx_mp4_mdhd_atom_t *mdhd_atom; + ngx_mp4_mdhd64_atom_t *mdhd64_atom; + + atom = trak->out[NGX_HTTP_MP4_MDHD_ATOM].buf; + if (atom == NULL) { + return; + } + + mdhd_atom = (ngx_mp4_mdhd_atom_t *) atom->pos; + mdhd64_atom = (ngx_mp4_mdhd64_atom_t *) atom->pos; + + if (mdhd_atom->version[0] == 0) { + ngx_mp4_set_32value(mdhd_atom->duration, trak->duration); + + } else { + ngx_mp4_set_64value(mdhd64_atom->duration, trak->duration); + } + + trak->size += trak->mdhd_size; +} + + static ngx_int_t ngx_http_mp4_read_hdlr_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) { -- cgit From 7927071ee26ff6313301b744a90240dccbc836db Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Thu, 28 Oct 2021 14:14:25 +0300 Subject: Mp4: mp4_start_key_frame directive. The directive enables including all frames from start time to the most recent key frame in the result. Those frames are removed from presentation timeline using mp4 edit lists. Edit lists are currently supported by popular players and browsers such as Chrome, Safari, QuickTime and ffmpeg. Among those not supporting them properly is Firefox[1]. Based on a patch by Tracey Jaquith, Internet Archive. [1] https://bugzilla.mozilla.org/show_bug.cgi?id=1735300 --- src/http/modules/ngx_http_mp4_module.c | 221 +++++++++++++++++++++++++++++---- 1 file changed, 194 insertions(+), 27 deletions(-) (limited to 'src/http') diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c index fab8e2ca2..9c3f627fe 100644 --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -11,31 +11,33 @@ #define NGX_HTTP_MP4_TRAK_ATOM 0 #define NGX_HTTP_MP4_TKHD_ATOM 1 -#define NGX_HTTP_MP4_MDIA_ATOM 2 -#define NGX_HTTP_MP4_MDHD_ATOM 3 -#define NGX_HTTP_MP4_HDLR_ATOM 4 -#define NGX_HTTP_MP4_MINF_ATOM 5 -#define NGX_HTTP_MP4_VMHD_ATOM 6 -#define NGX_HTTP_MP4_SMHD_ATOM 7 -#define NGX_HTTP_MP4_DINF_ATOM 8 -#define NGX_HTTP_MP4_STBL_ATOM 9 -#define NGX_HTTP_MP4_STSD_ATOM 10 -#define NGX_HTTP_MP4_STTS_ATOM 11 -#define NGX_HTTP_MP4_STTS_DATA 12 -#define NGX_HTTP_MP4_STSS_ATOM 13 -#define NGX_HTTP_MP4_STSS_DATA 14 -#define NGX_HTTP_MP4_CTTS_ATOM 15 -#define NGX_HTTP_MP4_CTTS_DATA 16 -#define NGX_HTTP_MP4_STSC_ATOM 17 -#define NGX_HTTP_MP4_STSC_START 18 -#define NGX_HTTP_MP4_STSC_DATA 19 -#define NGX_HTTP_MP4_STSC_END 20 -#define NGX_HTTP_MP4_STSZ_ATOM 21 -#define NGX_HTTP_MP4_STSZ_DATA 22 -#define NGX_HTTP_MP4_STCO_ATOM 23 -#define NGX_HTTP_MP4_STCO_DATA 24 -#define NGX_HTTP_MP4_CO64_ATOM 25 -#define NGX_HTTP_MP4_CO64_DATA 26 +#define NGX_HTTP_MP4_EDTS_ATOM 2 +#define NGX_HTTP_MP4_ELST_ATOM 3 +#define NGX_HTTP_MP4_MDIA_ATOM 4 +#define NGX_HTTP_MP4_MDHD_ATOM 5 +#define NGX_HTTP_MP4_HDLR_ATOM 6 +#define NGX_HTTP_MP4_MINF_ATOM 7 +#define NGX_HTTP_MP4_VMHD_ATOM 8 +#define NGX_HTTP_MP4_SMHD_ATOM 9 +#define NGX_HTTP_MP4_DINF_ATOM 10 +#define NGX_HTTP_MP4_STBL_ATOM 11 +#define NGX_HTTP_MP4_STSD_ATOM 12 +#define NGX_HTTP_MP4_STTS_ATOM 13 +#define NGX_HTTP_MP4_STTS_DATA 14 +#define NGX_HTTP_MP4_STSS_ATOM 15 +#define NGX_HTTP_MP4_STSS_DATA 16 +#define NGX_HTTP_MP4_CTTS_ATOM 17 +#define NGX_HTTP_MP4_CTTS_DATA 18 +#define NGX_HTTP_MP4_STSC_ATOM 19 +#define NGX_HTTP_MP4_STSC_START 20 +#define NGX_HTTP_MP4_STSC_DATA 21 +#define NGX_HTTP_MP4_STSC_END 22 +#define NGX_HTTP_MP4_STSZ_ATOM 23 +#define NGX_HTTP_MP4_STSZ_DATA 24 +#define NGX_HTTP_MP4_STCO_ATOM 25 +#define NGX_HTTP_MP4_STCO_DATA 26 +#define NGX_HTTP_MP4_CO64_ATOM 27 +#define NGX_HTTP_MP4_CO64_DATA 28 #define NGX_HTTP_MP4_LAST_ATOM NGX_HTTP_MP4_CO64_DATA @@ -43,6 +45,7 @@ typedef struct { size_t buffer_size; size_t max_buffer_size; + ngx_flag_t start_key_frame; } ngx_http_mp4_conf_t; @@ -53,6 +56,25 @@ typedef struct { } ngx_mp4_stsc_entry_t; +typedef struct { + u_char size[4]; + u_char name[4]; +} ngx_mp4_edts_atom_t; + + +typedef struct { + u_char size[4]; + u_char name[4]; + u_char version[1]; + u_char flags[3]; + u_char entries[4]; + u_char duration[8]; + u_char media_time[8]; + u_char media_rate[2]; + u_char reserved[2]; +} ngx_mp4_elst_atom_t; + + typedef struct { uint32_t timescale; uint32_t time_to_sample_entries; @@ -71,6 +93,8 @@ typedef struct { uint64_t start_chunk_samples_size; uint64_t end_chunk_samples_size; uint64_t duration; + uint64_t prefix; + uint64_t movie_duration; off_t start_offset; off_t end_offset; @@ -86,6 +110,8 @@ typedef struct { ngx_buf_t trak_atom_buf; ngx_buf_t tkhd_atom_buf; + ngx_buf_t edts_atom_buf; + ngx_buf_t elst_atom_buf; ngx_buf_t mdia_atom_buf; ngx_buf_t mdhd_atom_buf; ngx_buf_t hdlr_atom_buf; @@ -112,6 +138,8 @@ typedef struct { ngx_buf_t co64_atom_buf; ngx_buf_t co64_data_buf; + ngx_mp4_edts_atom_t edts_atom; + ngx_mp4_elst_atom_t elst_atom; ngx_mp4_stsc_entry_t stsc_start_chunk_entry; ngx_mp4_stsc_entry_t stsc_end_chunk_entry; } ngx_http_mp4_trak_t; @@ -187,6 +215,14 @@ typedef struct { ((u_char *) (p))[6] = n3; \ ((u_char *) (p))[7] = n4 +#define ngx_mp4_get_16value(p) \ + ( ((uint16_t) ((u_char *) (p))[0] << 8) \ + + ( ((u_char *) (p))[1]) ) + +#define ngx_mp4_set_16value(p, n) \ + ((u_char *) (p))[0] = (u_char) ((n) >> 8); \ + ((u_char *) (p))[1] = (u_char) (n) + #define ngx_mp4_get_32value(p) \ ( ((uint32_t) ((u_char *) (p))[0] << 24) \ + ( ((u_char *) (p))[1] << 16) \ @@ -270,6 +306,8 @@ static ngx_int_t ngx_http_mp4_read_smhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); static ngx_int_t ngx_http_mp4_read_stbl_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); +static void ngx_http_mp4_update_edts_atom(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak); static void ngx_http_mp4_update_stbl_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak); static ngx_int_t ngx_http_mp4_read_stsd_atom(ngx_http_mp4_file_t *mp4, @@ -280,6 +318,8 @@ static ngx_int_t ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak); static ngx_int_t ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak, ngx_uint_t start); +static uint32_t ngx_http_mp4_seek_key_frame(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak, uint32_t start_sample); static ngx_int_t ngx_http_mp4_read_stss_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); static ngx_int_t ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4, @@ -343,6 +383,13 @@ static ngx_command_t ngx_http_mp4_commands[] = { offsetof(ngx_http_mp4_conf_t, max_buffer_size), NULL }, + { ngx_string("mp4_start_key_frame"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_mp4_conf_t, start_key_frame), + NULL }, + ngx_null_command }; @@ -829,6 +876,7 @@ ngx_http_mp4_process(ngx_http_mp4_file_t *mp4) trak[i].size += trak[i].hdlr_size; ngx_http_mp4_update_mdia_atom(mp4, &trak[i]); trak[i].size += trak[i].tkhd_size; + ngx_http_mp4_update_edts_atom(mp4, &trak[i]); ngx_http_mp4_update_trak_atom(mp4, &trak[i]); mp4->moov_size += trak[i].size; @@ -1590,6 +1638,7 @@ ngx_http_mp4_read_tkhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) trak = ngx_mp4_last_trak(mp4); trak->tkhd_size = atom_size; + trak->movie_duration = duration; ngx_mp4_set_32value(tkhd_atom->size, atom_size); @@ -1985,6 +2034,59 @@ ngx_http_mp4_read_stbl_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) } +static void +ngx_http_mp4_update_edts_atom(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak) +{ + ngx_buf_t *atom; + ngx_mp4_elst_atom_t *elst_atom; + ngx_mp4_edts_atom_t *edts_atom; + + if (trak->prefix == 0) { + return; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "mp4 edts atom update prefix:%uL", trak->prefix); + + edts_atom = &trak->edts_atom; + ngx_mp4_set_32value(edts_atom->size, sizeof(ngx_mp4_edts_atom_t) + + sizeof(ngx_mp4_elst_atom_t)); + ngx_mp4_set_atom_name(edts_atom, 'e', 'd', 't', 's'); + + atom = &trak->edts_atom_buf; + atom->temporary = 1; + atom->pos = (u_char *) edts_atom; + atom->last = (u_char *) edts_atom + sizeof(ngx_mp4_edts_atom_t); + + trak->out[NGX_HTTP_MP4_EDTS_ATOM].buf = atom; + + elst_atom = &trak->elst_atom; + ngx_mp4_set_32value(elst_atom->size, sizeof(ngx_mp4_elst_atom_t)); + ngx_mp4_set_atom_name(elst_atom, 'e', 'l', 's', 't'); + + elst_atom->version[0] = 1; + elst_atom->flags[0] = 0; + elst_atom->flags[1] = 0; + elst_atom->flags[2] = 0; + + ngx_mp4_set_32value(elst_atom->entries, 1); + ngx_mp4_set_64value(elst_atom->duration, trak->movie_duration); + ngx_mp4_set_64value(elst_atom->media_time, trak->prefix); + ngx_mp4_set_16value(elst_atom->media_rate, 1); + ngx_mp4_set_16value(elst_atom->reserved, 0); + + atom = &trak->elst_atom_buf; + atom->temporary = 1; + atom->pos = (u_char *) elst_atom; + atom->last = (u_char *) elst_atom + sizeof(ngx_mp4_elst_atom_t); + + trak->out[NGX_HTTP_MP4_ELST_ATOM].buf = atom; + + trak->size += sizeof(ngx_mp4_edts_atom_t) + sizeof(ngx_mp4_elst_atom_t); +} + + static void ngx_http_mp4_update_stbl_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak) @@ -2183,7 +2285,7 @@ static ngx_int_t ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak, ngx_uint_t start) { - uint32_t count, duration, rest; + uint32_t count, duration, rest, key_prefix; uint64_t start_time; ngx_buf_t *data; ngx_uint_t start_sample, entries, start_sec; @@ -2207,7 +2309,7 @@ ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, data = trak->out[NGX_HTTP_MP4_STTS_DATA].buf; - start_time = (uint64_t) start_sec * trak->timescale / 1000; + start_time = (uint64_t) start_sec * trak->timescale / 1000 + trak->prefix; entries = trak->time_to_sample_entries; start_sample = 0; @@ -2253,6 +2355,26 @@ ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, found: if (start) { + key_prefix = ngx_http_mp4_seek_key_frame(mp4, trak, start_sample); + + start_sample -= key_prefix; + + while (rest < key_prefix) { + trak->prefix += rest * duration; + key_prefix -= rest; + + entry--; + entries++; + + count = ngx_mp4_get_32value(entry->count); + duration = ngx_mp4_get_32value(entry->duration); + rest = count; + } + + trak->prefix += key_prefix * duration; + trak->duration += trak->prefix; + rest -= key_prefix; + ngx_mp4_set_32value(entry->count, count - rest); data->pos = (u_char *) entry; trak->time_to_sample_entries = entries; @@ -2277,6 +2399,49 @@ found: } +static uint32_t +ngx_http_mp4_seek_key_frame(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak, + uint32_t start_sample) +{ + uint32_t key_prefix, sample, *entry, *end; + ngx_buf_t *data; + ngx_http_mp4_conf_t *conf; + + conf = ngx_http_get_module_loc_conf(mp4->request, ngx_http_mp4_module); + if (!conf->start_key_frame) { + return 0; + } + + data = trak->out[NGX_HTTP_MP4_STSS_DATA].buf; + if (data == NULL) { + return 0; + } + + entry = (uint32_t *) data->pos; + end = (uint32_t *) data->last; + + /* sync samples starts from 1 */ + start_sample++; + + key_prefix = 0; + + while (entry < end) { + sample = ngx_mp4_get_32value(entry); + if (sample > start_sample) { + break; + } + + key_prefix = start_sample - sample; + entry++; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "mp4 key frame prefix:%uD", key_prefix); + + return key_prefix; +} + + typedef struct { u_char size[4]; u_char name[4]; @@ -3614,6 +3779,7 @@ ngx_http_mp4_create_conf(ngx_conf_t *cf) conf->buffer_size = NGX_CONF_UNSET_SIZE; conf->max_buffer_size = NGX_CONF_UNSET_SIZE; + conf->start_key_frame = NGX_CONF_UNSET; return conf; } @@ -3628,6 +3794,7 @@ ngx_http_mp4_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, 512 * 1024); ngx_conf_merge_size_value(conf->max_buffer_size, prev->max_buffer_size, 10 * 1024 * 1024); + ngx_conf_merge_value(conf->start_key_frame, prev->start_key_frame, 0); return NGX_CONF_OK; } -- cgit From f3fdc4c96f3cd1c338ecf11a67acfae6d0a08dc7 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Fri, 29 Oct 2021 20:21:43 +0300 Subject: Switched to using posted next events after sendfile_max_chunk. Previously, 1 millisecond delay was used instead. In certain edge cases this might result in noticeable performance degradation though, notably on Linux with typical CONFIG_HZ=250 (so 1ms delay becomes 4ms), sendfile_max_chunk 2m, and link speed above 2.5 Gbps. Using posted next events removes the artificial delay and makes processing fast in all cases. --- src/http/ngx_http_write_filter_module.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/http') diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c index 6a5d957b1..bd3770457 100644 --- a/src/http/ngx_http_write_filter_module.c +++ b/src/http/ngx_http_write_filter_module.c @@ -331,8 +331,7 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) && c->write->ready && c->sent - sent >= limit - (off_t) (2 * ngx_pagesize)) { - c->write->delayed = 1; - ngx_add_timer(c->write, 1); + ngx_post_event(c->write, &ngx_posted_next_events); } for (cl = r->out; cl && cl != chain; /* void */) { -- cgit From 00f4be1ce498df08e097925b08cfb1f84a8fda29 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Fri, 29 Oct 2021 20:21:48 +0300 Subject: Simplified sendfile_max_chunk handling. Previously, it was checked that sendfile_max_chunk was enabled and almost whole sendfile_max_chunk was sent (see e67ef50c3176), to avoid delaying connections where sendfile_max_chunk wasn't reached (for example, when sending responses smaller than sendfile_max_chunk). Now we instead check if there are unsent data, and the connection is still ready for writing. Additionally we also check c->write->delayed to ignore connections already delayed by limit_rate. This approach is believed to be more robust, and correctly handles not only sendfile_max_chunk, but also internal limits of c->send_chain(), such as sendfile() maximum supported length (ticket #1870). --- src/http/ngx_http_write_filter_module.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'src/http') diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c index bd3770457..932f26dd3 100644 --- a/src/http/ngx_http_write_filter_module.c +++ b/src/http/ngx_http_write_filter_module.c @@ -321,16 +321,12 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) delay = (ngx_msec_t) ((nsent - sent) * 1000 / r->limit_rate); if (delay > 0) { - limit = 0; c->write->delayed = 1; ngx_add_timer(c->write, delay); } } - if (limit - && c->write->ready - && c->sent - sent >= limit - (off_t) (2 * ngx_pagesize)) - { + if (chain && c->write->ready && !c->write->delayed) { ngx_post_event(c->write, &ngx_posted_next_events); } -- cgit From b3b368184b1e3c82da6703e8d7367f38fdc98d1a Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Fri, 29 Oct 2021 20:21:54 +0300 Subject: Upstream: sendfile_max_chunk support. Previously, connections to upstream servers used sendfile() if it was enabled, but never honored sendfile_max_chunk. This might result in worker monopolization for a long time if large request bodies are allowed. --- src/http/ngx_http_upstream.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/http') diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index daa8d2201..002b3e65d 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -1511,8 +1511,9 @@ ngx_http_upstream_check_broken_connection(ngx_http_request_t *r, static void ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) { - ngx_int_t rc; - ngx_connection_t *c; + ngx_int_t rc; + ngx_connection_t *c; + ngx_http_core_loc_conf_t *clcf; r->connection->log->action = "connecting to upstream"; @@ -1599,10 +1600,12 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) /* init or reinit the ngx_output_chain() and ngx_chain_writer() contexts */ + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + u->writer.out = NULL; u->writer.last = &u->writer.out; u->writer.connection = c; - u->writer.limit = 0; + u->writer.limit = clcf->sendfile_max_chunk; if (u->request_sent) { if (ngx_http_upstream_reinit(r, u) != NGX_OK) { -- cgit From 5636e7f7b491a4db287e3aa5312cd5955075f5ec Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Fri, 29 Oct 2021 20:21:57 +0300 Subject: Changed default value of sendfile_max_chunk to 2m. The "sendfile_max_chunk" directive is important to prevent worker monopolization by fast connections. The 2m value implies maximum 200ms delay with 100 Mbps links, 20ms delay with 1 Gbps links, and 2ms on 10 Gbps links. It also seems to be a good value for disks. --- src/http/ngx_http_core_module.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/http') diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index bad43ea5c..fe1da4576 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -3720,7 +3720,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->internal, prev->internal, 0); ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0); ngx_conf_merge_size_value(conf->sendfile_max_chunk, - prev->sendfile_max_chunk, 0); + prev->sendfile_max_chunk, 2 * 1024 * 1024); ngx_conf_merge_size_value(conf->subrequest_output_buffer_size, prev->subrequest_output_buffer_size, (size_t) ngx_pagesize); -- cgit