changeset 8942:5c86189a1c1b quic

Merged with the default branch.
author Ruslan Ermilov <ru@nginx.com>
date Fri, 24 Dec 2021 15:53:59 +0300
parents 0433e69f5425 (current diff) 336084ff943b (diff)
children 118a34e32121
files auto/modules auto/sources src/event/ngx_event_openssl.c src/event/ngx_event_openssl.h src/http/modules/ngx_http_ssl_module.c src/http/ngx_http.h src/http/ngx_http_upstream.c src/http/v2/ngx_http_v2.h src/http/v3/ngx_http_v3_encode.c src/http/v3/ngx_http_v3_parse.c src/stream/ngx_stream_ssl_module.c
diffstat 21 files changed, 261 insertions(+), 90 deletions(-) [+]
line wrap: on
line diff
--- a/auto/modules
+++ b/auto/modules
@@ -102,6 +102,11 @@ if [ $HTTP = YES ]; then
     fi
 
 
+    if [ $HTTP_V2 = YES -o $HTTP_V3 = YES ]; then
+        HTTP_SRCS="$HTTP_SRCS $HTTP_HUFF_SRCS"
+    fi
+
+
     # the module order is important
     #     ngx_http_static_module
     #     ngx_http_gzip_static_module
@@ -427,8 +432,6 @@ if [ $HTTP = YES ]; then
         ngx_module_srcs="src/http/v2/ngx_http_v2.c \
                          src/http/v2/ngx_http_v2_table.c \
                          src/http/v2/ngx_http_v2_encode.c \
-                         src/http/v2/ngx_http_v2_huff_decode.c \
-                         src/http/v2/ngx_http_v2_huff_encode.c \
                          src/http/v2/ngx_http_v2_module.c"
         ngx_module_libs=
         ngx_module_link=$HTTP_V2
@@ -460,12 +463,6 @@ if [ $HTTP = YES ]; then
         ngx_module_libs=
         ngx_module_link=$HTTP_V3
 
-        if [ $HTTP_V2 = NO ]; then
-            ngx_module_srcs="$ngx_module_srcs \
-                             src/http/v2/ngx_http_v2_huff_decode.c \
-                             src/http/v2/ngx_http_v2_huff_encode.c"
-        fi
-
         . auto/module
     fi
 
--- a/auto/sources
+++ b/auto/sources
@@ -256,3 +256,6 @@ NGX_WIN32_RC="src/os/win32/nginx.rc"
 
 
 HTTP_FILE_CACHE_SRCS=src/http/ngx_http_file_cache.c
+
+HTTP_HUFF_SRCS="src/http/ngx_http_huff_decode.c
+                src/http/ngx_http_huff_encode.c"
--- a/contrib/vim/syntax/nginx.vim
+++ b/contrib/vim/syntax/nginx.vim
@@ -152,6 +152,7 @@ syn keyword ngxDirective contained auth_
 syn keyword ngxDirective contained auth_jwt_key_file
 syn keyword ngxDirective contained auth_jwt_key_request
 syn keyword ngxDirective contained auth_jwt_leeway
+syn keyword ngxDirective contained auth_jwt_require
 syn keyword ngxDirective contained auth_jwt_type
 syn keyword ngxDirective contained auth_request
 syn keyword ngxDirective contained auth_request_set
@@ -335,6 +336,10 @@ syn keyword ngxDirective contained ip_ha
 syn keyword ngxDirective contained js_access
 syn keyword ngxDirective contained js_body_filter
 syn keyword ngxDirective contained js_content
+syn keyword ngxDirective contained js_fetch_ciphers
+syn keyword ngxDirective contained js_fetch_protocols
+syn keyword ngxDirective contained js_fetch_trusted_certificate
+syn keyword ngxDirective contained js_fetch_verify_depth
 syn keyword ngxDirective contained js_filter
 syn keyword ngxDirective contained js_header_filter
 syn keyword ngxDirective contained js_import
@@ -402,6 +407,7 @@ syn keyword ngxDirective contained mp4_b
 syn keyword ngxDirective contained mp4_limit_rate
 syn keyword ngxDirective contained mp4_limit_rate_after
 syn keyword ngxDirective contained mp4_max_buffer_size
+syn keyword ngxDirective contained mp4_start_key_frame
 syn keyword ngxDirective contained msie_padding
 syn keyword ngxDirective contained msie_refresh
 syn keyword ngxDirective contained multi_accept
@@ -458,6 +464,7 @@ syn keyword ngxDirective contained proxy
 syn keyword ngxDirective contained proxy_cookie_path
 syn keyword ngxDirective contained proxy_download_rate
 syn keyword ngxDirective contained proxy_force_ranges
+syn keyword ngxDirective contained proxy_half_close
 syn keyword ngxDirective contained proxy_headers_hash_bucket_size
 syn keyword ngxDirective contained proxy_headers_hash_max_size
 syn keyword ngxDirective contained proxy_hide_header
@@ -597,6 +604,7 @@ syn keyword ngxDirective contained ssi_m
 syn keyword ngxDirective contained ssi_silent_errors
 syn keyword ngxDirective contained ssi_types
 syn keyword ngxDirective contained ssi_value_length
+syn keyword ngxDirective contained ssl_alpn
 syn keyword ngxDirective contained ssl_buffer_size
 syn keyword ngxDirective contained ssl_certificate
 syn keyword ngxDirective contained ssl_certificate_key
@@ -788,11 +796,15 @@ syn keyword ngxDirectiveThirdParty conta
 syn keyword ngxDirectiveThirdParty contained auth_gss
 syn keyword ngxDirectiveThirdParty contained auth_gss_allow_basic_fallback
 syn keyword ngxDirectiveThirdParty contained auth_gss_authorized_principal
+syn keyword ngxDirectiveThirdParty contained auth_gss_authorized_principal_regex
+syn keyword ngxDirectiveThirdParty contained auth_gss_constrained_delegation
+syn keyword ngxDirectiveThirdParty contained auth_gss_delegate_credentials
 syn keyword ngxDirectiveThirdParty contained auth_gss_force_realm
 syn keyword ngxDirectiveThirdParty contained auth_gss_format_full
 syn keyword ngxDirectiveThirdParty contained auth_gss_keytab
 syn keyword ngxDirectiveThirdParty contained auth_gss_map_to_local
 syn keyword ngxDirectiveThirdParty contained auth_gss_realm
+syn keyword ngxDirectiveThirdParty contained auth_gss_service_ccache
 syn keyword ngxDirectiveThirdParty contained auth_gss_service_name
 
 " LDAP Authentication
@@ -969,7 +981,6 @@ syn keyword ngxDirectiveThirdParty conta
 syn keyword ngxDirectiveThirdParty contained fancyindex_hide_symlinks
 syn keyword ngxDirectiveThirdParty contained fancyindex_ignore
 syn keyword ngxDirectiveThirdParty contained fancyindex_localtime
-syn keyword ngxDirectiveThirdParty contained fancyindex_name_length
 syn keyword ngxDirectiveThirdParty contained fancyindex_show_dotfiles
 syn keyword ngxDirectiveThirdParty contained fancyindex_show_path
 syn keyword ngxDirectiveThirdParty contained fancyindex_time_format
@@ -1059,7 +1070,9 @@ syn keyword ngxDirectiveThirdParty conta
 syn keyword ngxDirectiveThirdParty contained nchan_pubsub
 syn keyword ngxDirectiveThirdParty contained nchan_pubsub_channel_id
 syn keyword ngxDirectiveThirdParty contained nchan_pubsub_location
+syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_check_interval
 syn keyword ngxDirectiveThirdParty contained nchan_redis_connect_timeout
+syn keyword ngxDirectiveThirdParty contained nchan_redis_discovered_ip_range_blacklist
 syn keyword ngxDirectiveThirdParty contained nchan_redis_fakesub_timer_interval
 syn keyword ngxDirectiveThirdParty contained nchan_redis_idle_channel_cache_timeout
 syn keyword ngxDirectiveThirdParty contained nchan_redis_namespace
@@ -1067,12 +1080,29 @@ syn keyword ngxDirectiveThirdParty conta
 syn keyword ngxDirectiveThirdParty contained nchan_redis_optimize_target
 syn keyword ngxDirectiveThirdParty contained nchan_redis_pass
 syn keyword ngxDirectiveThirdParty contained nchan_redis_pass_inheritable
+syn keyword ngxDirectiveThirdParty contained nchan_redis_password
 syn keyword ngxDirectiveThirdParty contained nchan_redis_ping_interval
 syn keyword ngxDirectiveThirdParty contained nchan_redis_publish_msgpacked_max_size
 syn keyword ngxDirectiveThirdParty contained nchan_redis_server
+syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl
+syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl_ciphers
+syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl_client_certificate
+syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl_client_certificate_key
+syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl_server_name
+syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl_trusted_certificate
+syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl_trusted_certificate_path
+syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl_verify_certificate
 syn keyword ngxDirectiveThirdParty contained nchan_redis_storage_mode
 syn keyword ngxDirectiveThirdParty contained nchan_redis_subscribe_weights
+syn keyword ngxDirectiveThirdParty contained nchan_redis_tls
+syn keyword ngxDirectiveThirdParty contained nchan_redis_tls_ciphers
+syn keyword ngxDirectiveThirdParty contained nchan_redis_tls_client_certificate
+syn keyword ngxDirectiveThirdParty contained nchan_redis_tls_server_name
+syn keyword ngxDirectiveThirdParty contained nchan_redis_tls_trusted_certificate
+syn keyword ngxDirectiveThirdParty contained nchan_redis_tls_trusted_certificate_path
+syn keyword ngxDirectiveThirdParty contained nchan_redis_tls_verify_certificate
 syn keyword ngxDirectiveThirdParty contained nchan_redis_url
+syn keyword ngxDirectiveThirdParty contained nchan_redis_username
 syn keyword ngxDirectiveThirdParty contained nchan_redis_wait_after_connecting
 syn keyword ngxDirectiveThirdParty contained nchan_shared_memory_size
 syn keyword ngxDirectiveThirdParty contained nchan_storage_engine
@@ -1385,6 +1415,7 @@ syn keyword ngxDirectiveThirdParty conta
 syn keyword ngxDirectiveThirdParty contained lua_socket_send_lowat
 syn keyword ngxDirectiveThirdParty contained lua_socket_send_timeout
 syn keyword ngxDirectiveThirdParty contained lua_ssl_ciphers
+syn keyword ngxDirectiveThirdParty contained lua_ssl_conf_command
 syn keyword ngxDirectiveThirdParty contained lua_ssl_crl
 syn keyword ngxDirectiveThirdParty contained lua_ssl_protocols
 syn keyword ngxDirectiveThirdParty contained lua_ssl_trusted_certificate
@@ -1392,6 +1423,7 @@ syn keyword ngxDirectiveThirdParty conta
 syn keyword ngxDirectiveThirdParty contained lua_thread_cache_max_entries
 syn keyword ngxDirectiveThirdParty contained lua_transform_underscores_in_response_headers
 syn keyword ngxDirectiveThirdParty contained lua_use_default_type
+syn keyword ngxDirectiveThirdParty contained lua_worker_thread_vm_pool_size
 syn keyword ngxDirectiveThirdParty contained rewrite_by_lua
 syn keyword ngxDirectiveThirdParty contained rewrite_by_lua_block
 syn keyword ngxDirectiveThirdParty contained rewrite_by_lua_file
@@ -1401,6 +1433,8 @@ syn keyword ngxDirectiveThirdParty conta
 syn keyword ngxDirectiveThirdParty contained set_by_lua_file
 syn keyword ngxDirectiveThirdParty contained ssl_certificate_by_lua_block
 syn keyword ngxDirectiveThirdParty contained ssl_certificate_by_lua_file
+syn keyword ngxDirectiveThirdParty contained ssl_client_hello_by_lua_block
+syn keyword ngxDirectiveThirdParty contained ssl_client_hello_by_lua_file
 syn keyword ngxDirectiveThirdParty contained ssl_session_fetch_by_lua_block
 syn keyword ngxDirectiveThirdParty contained ssl_session_fetch_by_lua_file
 syn keyword ngxDirectiveThirdParty contained ssl_session_store_by_lua_block
@@ -1719,15 +1753,18 @@ syn keyword ngxDirectiveThirdParty conta
 syn keyword ngxDirectiveThirdParty contained set_base32_padding
 syn keyword ngxDirectiveThirdParty contained set_decode_base32
 syn keyword ngxDirectiveThirdParty contained set_decode_base64
+syn keyword ngxDirectiveThirdParty contained set_decode_base64url
 syn keyword ngxDirectiveThirdParty contained set_decode_hex
 syn keyword ngxDirectiveThirdParty contained set_encode_base32
 syn keyword ngxDirectiveThirdParty contained set_encode_base64
+syn keyword ngxDirectiveThirdParty contained set_encode_base64url
 syn keyword ngxDirectiveThirdParty contained set_encode_hex
 syn keyword ngxDirectiveThirdParty contained set_escape_uri
 syn keyword ngxDirectiveThirdParty contained set_formatted_gmt_time
 syn keyword ngxDirectiveThirdParty contained set_formatted_local_time
 syn keyword ngxDirectiveThirdParty contained set_hashed_upstream
 syn keyword ngxDirectiveThirdParty contained set_hmac_sha1
+syn keyword ngxDirectiveThirdParty contained set_hmac_sha256
 syn keyword ngxDirectiveThirdParty contained set_if_empty
 syn keyword ngxDirectiveThirdParty contained set_local_today
 syn keyword ngxDirectiveThirdParty contained set_misc_base32_padding
@@ -1849,6 +1886,7 @@ syn keyword ngxDirectiveThirdParty conta
 syn keyword ngxDirectiveThirdParty contained vod_open_file_thread_pool
 syn keyword ngxDirectiveThirdParty contained vod_output_buffer_pool
 syn keyword ngxDirectiveThirdParty contained vod_parse_hdlr_name
+syn keyword ngxDirectiveThirdParty contained vod_parse_udta_name
 syn keyword ngxDirectiveThirdParty contained vod_path_response_postfix
 syn keyword ngxDirectiveThirdParty contained vod_path_response_prefix
 syn keyword ngxDirectiveThirdParty contained vod_performance_counters
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -9,8 +9,8 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define nginx_version      1021004
-#define NGINX_VERSION      "1.21.4"
+#define nginx_version      1021005
+#define NGINX_VERSION      "1.21.5"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #ifdef NGX_BUILD
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -4741,6 +4741,42 @@ ngx_ssl_get_ciphers(ngx_connection_t *c,
 
 
 ngx_int_t
+ngx_ssl_get_curve(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
+{
+#ifdef SSL_get_negotiated_group
+
+    int  nid;
+
+    nid = SSL_get_negotiated_group(c->ssl->connection);
+
+    if (nid != NID_undef) {
+
+        if ((nid & TLSEXT_nid_unknown) == 0) {
+            s->len = ngx_strlen(OBJ_nid2sn(nid));
+            s->data = (u_char *) OBJ_nid2sn(nid);
+            return NGX_OK;
+        }
+
+        s->len = sizeof("0x0000") - 1;
+
+        s->data = ngx_pnalloc(pool, s->len);
+        if (s->data == NULL) {
+            return NGX_ERROR;
+        }
+
+        ngx_sprintf(s->data, "0x%04xd", nid & 0xffff);
+
+        return NGX_OK;
+    }
+
+#endif
+
+    s->len = 0;
+    return NGX_OK;
+}
+
+
+ngx_int_t
 ngx_ssl_get_curves(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
 {
 #ifdef SSL_CTRL_GET_CURVES
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -264,6 +264,8 @@ ngx_int_t ngx_ssl_get_cipher_name(ngx_co
     ngx_str_t *s);
 ngx_int_t ngx_ssl_get_ciphers(ngx_connection_t *c, ngx_pool_t *pool,
     ngx_str_t *s);
+ngx_int_t ngx_ssl_get_curve(ngx_connection_t *c, ngx_pool_t *pool,
+    ngx_str_t *s);
 ngx_int_t ngx_ssl_get_curves(ngx_connection_t *c, ngx_pool_t *pool,
     ngx_str_t *s);
 ngx_int_t ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool,
--- a/src/http/modules/ngx_http_grpc_module.c
+++ b/src/http/modules/ngx_http_grpc_module.c
@@ -3180,10 +3180,10 @@ ngx_http_grpc_parse_fragment(ngx_http_re
             ctx->field_rest -= size;
 
             if (ctx->field_huffman) {
-                if (ngx_http_v2_huff_decode(&ctx->field_state, p, size,
-                                            &ctx->field_end,
-                                            ctx->field_rest == 0,
-                                            r->connection->log)
+                if (ngx_http_huff_decode(&ctx->field_state, p, size,
+                                         &ctx->field_end,
+                                         ctx->field_rest == 0,
+                                         r->connection->log)
                     != NGX_OK)
                 {
                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
@@ -3289,10 +3289,10 @@ ngx_http_grpc_parse_fragment(ngx_http_re
             ctx->field_rest -= size;
 
             if (ctx->field_huffman) {
-                if (ngx_http_v2_huff_decode(&ctx->field_state, p, size,
-                                            &ctx->field_end,
-                                            ctx->field_rest == 0,
-                                            r->connection->log)
+                if (ngx_http_huff_decode(&ctx->field_state, p, size,
+                                         &ctx->field_end,
+                                         ctx->field_rest == 0,
+                                         r->connection->log)
                     != NGX_OK)
                 {
                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -342,6 +342,9 @@ static ngx_http_variable_t  ngx_http_ssl
     { ngx_string("ssl_ciphers"), NULL, ngx_http_ssl_variable,
       (uintptr_t) ngx_ssl_get_ciphers, NGX_HTTP_VAR_CHANGEABLE, 0 },
 
+    { ngx_string("ssl_curve"), NULL, ngx_http_ssl_variable,
+      (uintptr_t) ngx_ssl_get_curve, NGX_HTTP_VAR_CHANGEABLE, 0 },
+
     { ngx_string("ssl_curves"), NULL, ngx_http_ssl_variable,
       (uintptr_t) ngx_ssl_get_curves, NGX_HTTP_VAR_CHANGEABLE, 0 },
 
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -177,9 +177,9 @@ ngx_uint_t  ngx_http_degraded(ngx_http_r
 #endif
 
 #if (NGX_HTTP_V2 || NGX_HTTP_V3)
-ngx_int_t ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len,
+ngx_int_t ngx_http_huff_decode(u_char *state, u_char *src, size_t len,
     u_char **dst, ngx_uint_t last, ngx_log_t *log);
-size_t ngx_http_v2_huff_encode(u_char *src, size_t len, u_char *dst,
+size_t ngx_http_huff_encode(u_char *src, size_t len, u_char *dst,
     ngx_uint_t lower);
 #endif
 
--- a/src/http/ngx_http_copy_filter_module.c
+++ b/src/http/ngx_http_copy_filter_module.c
@@ -219,13 +219,25 @@ ngx_http_copy_aio_sendfile_preload(ngx_b
     ngx_http_request_t      *r;
     ngx_output_chain_ctx_t  *ctx;
 
+    aio = file->file->aio;
+    r = aio->data;
+
+    if (r->aio) {
+        /*
+         * tolerate sendfile() calls if another operation is already
+         * running; this can happen due to subrequests, multiple calls
+         * of the next body filter from a filter, or in HTTP/2 due to
+         * a write event on the main connection
+         */
+
+        return NGX_AGAIN;
+    }
+
     n = ngx_file_aio_read(file->file, buf, 1, file->file_pos, NULL);
 
     if (n == NGX_AGAIN) {
-        aio = file->file->aio;
         aio->handler = ngx_http_copy_aio_sendfile_event_handler;
 
-        r = aio->data;
         r->main->blocked++;
         r->aio = 1;
 
@@ -241,16 +253,32 @@ static void
 ngx_http_copy_aio_sendfile_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;
 
     r->main->blocked--;
     r->aio = 0;
     ev->complete = 0;
 
-    r->connection->write->handler(r->connection->write);
+#if (NGX_HTTP_V2)
+
+    if (r->stream) {
+        /*
+         * for HTTP/2, update write event to make sure processing will
+         * reach the main connection to handle sendfile() preload
+         */
+
+        c->write->ready = 1;
+        c->write->active = 0;
+    }
+
+#endif
+
+    c->write->handler(c->write);
 }
 
 #endif
@@ -263,6 +291,7 @@ static ngx_int_t
 ngx_http_copy_thread_handler(ngx_thread_task_t *task, ngx_file_t *file)
 {
     ngx_str_t                  name;
+    ngx_connection_t          *c;
     ngx_thread_pool_t         *tp;
     ngx_http_request_t        *r;
     ngx_output_chain_ctx_t    *ctx;
@@ -270,6 +299,27 @@ ngx_http_copy_thread_handler(ngx_thread_
 
     r = file->thread_ctx;
 
+    if (r->aio) {
+        /*
+         * tolerate sendfile() calls if another operation is already
+         * running; this can happen due to subrequests, multiple calls
+         * of the next body filter from a filter, or in HTTP/2 due to
+         * a write event on the main connection
+         */
+
+        c = r->connection;
+
+#if (NGX_HTTP_V2)
+        if (r->stream) {
+            c = r->stream->connection->connection;
+        }
+#endif
+
+        if (task == c->sendfile_task) {
+            return NGX_OK;
+        }
+    }
+
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
     tp = clcf->thread_pool;
 
@@ -323,6 +373,20 @@ ngx_http_copy_thread_event_handler(ngx_e
     r->main->blocked--;
     r->aio = 0;
 
+#if (NGX_HTTP_V2)
+
+    if (r->stream) {
+        /*
+         * for HTTP/2, update write event to make sure processing will
+         * reach the main connection to handle sendfile() in threads
+         */
+
+        c->write->ready = 1;
+        c->write->active = 0;
+    }
+
+#endif
+
     if (r->done) {
         /*
          * trigger connection event handler if the subrequest was
rename from src/http/v2/ngx_http_v2_huff_decode.c
rename to src/http/ngx_http_huff_decode.c
--- a/src/http/v2/ngx_http_v2_huff_decode.c
+++ b/src/http/ngx_http_huff_decode.c
@@ -15,14 +15,14 @@ typedef struct {
     u_char  emit;
     u_char  sym;
     u_char  ending;
-} ngx_http_v2_huff_decode_code_t;
+} ngx_http_huff_decode_code_t;
 
 
-static ngx_inline ngx_int_t ngx_http_v2_huff_decode_bits(u_char *state,
+static ngx_inline ngx_int_t ngx_http_huff_decode_bits(u_char *state,
     u_char *ending, ngx_uint_t bits, u_char **dst);
 
 
-static ngx_http_v2_huff_decode_code_t  ngx_http_v2_huff_decode_codes[256][16] =
+static ngx_http_huff_decode_code_t  ngx_http_huff_decode_codes[256][16] =
 {
     /* 0 */
     {
@@ -2640,7 +2640,7 @@ static ngx_http_v2_huff_decode_code_t  n
 
 
 ngx_int_t
-ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst,
+ngx_http_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst,
     ngx_uint_t last, ngx_log_t *log)
 {
     u_char  *end, ch, ending;
@@ -2653,7 +2653,7 @@ ngx_http_v2_huff_decode(u_char *state, u
     while (src != end) {
         ch = *src++;
 
-        if (ngx_http_v2_huff_decode_bits(state, &ending, ch >> 4, dst)
+        if (ngx_http_huff_decode_bits(state, &ending, ch >> 4, dst)
             != NGX_OK)
         {
             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0,
@@ -2663,7 +2663,7 @@ ngx_http_v2_huff_decode(u_char *state, u
             return NGX_ERROR;
         }
 
-        if (ngx_http_v2_huff_decode_bits(state, &ending, ch & 0xf, dst)
+        if (ngx_http_huff_decode_bits(state, &ending, ch & 0xf, dst)
             != NGX_OK)
         {
             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0,
@@ -2692,12 +2692,12 @@ ngx_http_v2_huff_decode(u_char *state, u
 
 
 static ngx_inline ngx_int_t
-ngx_http_v2_huff_decode_bits(u_char *state, u_char *ending, ngx_uint_t bits,
+ngx_http_huff_decode_bits(u_char *state, u_char *ending, ngx_uint_t bits,
     u_char **dst)
 {
-    ngx_http_v2_huff_decode_code_t  code;
+    ngx_http_huff_decode_code_t  code;
 
-    code = ngx_http_v2_huff_decode_codes[*state][bits];
+    code = ngx_http_huff_decode_codes[*state][bits];
 
     if (code.next == *state) {
         return NGX_ERROR;
rename from src/http/v2/ngx_http_v2_huff_encode.c
rename to src/http/ngx_http_huff_encode.c
--- a/src/http/v2/ngx_http_v2_huff_encode.c
+++ b/src/http/ngx_http_huff_encode.c
@@ -14,10 +14,10 @@
 typedef struct {
     uint32_t  code;
     uint32_t  len;
-} ngx_http_v2_huff_encode_code_t;
+} ngx_http_huff_encode_code_t;
 
 
-static ngx_http_v2_huff_encode_code_t  ngx_http_v2_huff_encode_table[256] =
+static ngx_http_huff_encode_code_t  ngx_http_huff_encode_table[256] =
 {
     {0x00001ff8, 13}, {0x007fffd8, 23}, {0x0fffffe2, 28}, {0x0fffffe3, 28},
     {0x0fffffe4, 28}, {0x0fffffe5, 28}, {0x0fffffe6, 28}, {0x0fffffe7, 28},
@@ -87,7 +87,7 @@ static ngx_http_v2_huff_encode_code_t  n
 
 
 /* same as above, but embeds lowercase transformation */
-static ngx_http_v2_huff_encode_code_t  ngx_http_v2_huff_encode_table_lc[256] =
+static ngx_http_huff_encode_code_t  ngx_http_huff_encode_table_lc[256] =
 {
     {0x00001ff8, 13}, {0x007fffd8, 23}, {0x0fffffe2, 28}, {0x0fffffe3, 28},
     {0x0fffffe4, 28}, {0x0fffffe5, 28}, {0x0fffffe6, 28}, {0x0fffffe7, 28},
@@ -161,10 +161,10 @@ static ngx_http_v2_huff_encode_code_t  n
 #if (NGX_HAVE_LITTLE_ENDIAN)
 
 #if (NGX_HAVE_GCC_BSWAP64)
-#define ngx_http_v2_huff_encode_buf(dst, buf)                                 \
+#define ngx_http_huff_encode_buf(dst, buf)                                    \
     (*(uint64_t *) (dst) = __builtin_bswap64(buf))
 #else
-#define ngx_http_v2_huff_encode_buf(dst, buf)                                 \
+#define ngx_http_huff_encode_buf(dst, buf)                                    \
     ((dst)[0] = (u_char) ((buf) >> 56),                                       \
      (dst)[1] = (u_char) ((buf) >> 48),                                       \
      (dst)[2] = (u_char) ((buf) >> 40),                                       \
@@ -176,28 +176,28 @@ static ngx_http_v2_huff_encode_code_t  n
 #endif
 
 #else /* !NGX_HAVE_LITTLE_ENDIAN */
-#define ngx_http_v2_huff_encode_buf(dst, buf)                                 \
+#define ngx_http_huff_encode_buf(dst, buf)                                    \
     (*(uint64_t *) (dst) = (buf))
 #endif
 
 #else /* NGX_PTR_SIZE == 4 */
 
-#define ngx_http_v2_huff_encode_buf(dst, buf)                                 \
+#define ngx_http_huff_encode_buf(dst, buf)                                    \
     (*(uint32_t *) (dst) = htonl(buf))
 
 #endif
 
 
 size_t
-ngx_http_v2_huff_encode(u_char *src, size_t len, u_char *dst, ngx_uint_t lower)
+ngx_http_huff_encode(u_char *src, size_t len, u_char *dst, ngx_uint_t lower)
 {
-    u_char                          *end;
-    size_t                           hlen;
-    ngx_uint_t                       buf, pending, code;
-    ngx_http_v2_huff_encode_code_t  *table, *next;
+    u_char                       *end;
+    size_t                        hlen;
+    ngx_uint_t                    buf, pending, code;
+    ngx_http_huff_encode_code_t  *table, *next;
 
-    table = lower ? ngx_http_v2_huff_encode_table_lc
-                  : ngx_http_v2_huff_encode_table;
+    table = lower ? ngx_http_huff_encode_table_lc
+                  : ngx_http_huff_encode_table;
     hlen = 0;
     buf = 0;
     pending = 0;
@@ -224,7 +224,7 @@ ngx_http_v2_huff_encode(u_char *src, siz
 
         buf |= code >> pending;
 
-        ngx_http_v2_huff_encode_buf(&dst[hlen], buf);
+        ngx_http_huff_encode_buf(&dst[hlen], buf);
 
         hlen += sizeof(buf);
 
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -3867,6 +3867,7 @@ ngx_http_upstream_thread_handler(ngx_thr
 {
     ngx_str_t                  name;
     ngx_event_pipe_t          *p;
+    ngx_connection_t          *c;
     ngx_thread_pool_t         *tp;
     ngx_http_request_t        *r;
     ngx_http_core_loc_conf_t  *clcf;
@@ -3874,6 +3875,27 @@ ngx_http_upstream_thread_handler(ngx_thr
     r = file->thread_ctx;
     p = r->upstream->pipe;
 
+    if (r->aio) {
+        /*
+         * tolerate sendfile() calls if another operation is already
+         * running; this can happen due to subrequests, multiple calls
+         * of the next body filter from a filter, or in HTTP/2 due to
+         * a write event on the main connection
+         */
+
+        c = r->connection;
+
+#if (NGX_HTTP_V2)
+        if (r->stream) {
+            c = r->stream->connection->connection;
+        }
+#endif
+
+        if (task == c->sendfile_task) {
+            return NGX_OK;
+        }
+    }
+
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
     tp = clcf->thread_pool;
 
@@ -3925,6 +3947,20 @@ ngx_http_upstream_thread_event_handler(n
     r->main->blocked--;
     r->aio = 0;
 
+#if (NGX_HTTP_V2)
+
+    if (r->stream) {
+        /*
+         * for HTTP/2, update write event to make sure processing will
+         * reach the main connection to handle sendfile() in threads
+         */
+
+        c->write->ready = 1;
+        c->write->active = 0;
+    }
+
+#endif
+
     if (r->done) {
         /*
          * trigger connection event handler if the subrequest was
--- a/src/http/v2/ngx_http_v2.c
+++ b/src/http/v2/ngx_http_v2.c
@@ -1600,10 +1600,10 @@ ngx_http_v2_state_field_huff(ngx_http_v2
     h2c->state.length -= size;
     h2c->state.field_rest -= size;
 
-    if (ngx_http_v2_huff_decode(&h2c->state.field_state, pos, size,
-                                &h2c->state.field_end,
-                                h2c->state.field_rest == 0,
-                                h2c->connection->log)
+    if (ngx_http_huff_decode(&h2c->state.field_state, pos, size,
+                             &h2c->state.field_end,
+                             h2c->state.field_rest == 0,
+                             h2c->connection->log)
         != NGX_OK)
     {
         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
--- a/src/http/v2/ngx_http_v2_encode.c
+++ b/src/http/v2/ngx_http_v2_encode.c
@@ -20,7 +20,7 @@ ngx_http_v2_string_encode(u_char *dst, u
 {
     size_t  hlen;
 
-    hlen = ngx_http_v2_huff_encode(src, len, tmp, lower);
+    hlen = ngx_http_huff_encode(src, len, tmp, lower);
 
     if (hlen > 0) {
         *dst = NGX_HTTP_V2_ENCODE_HUFF;
--- a/src/http/v2/ngx_http_v2_filter_module.c
+++ b/src/http/v2/ngx_http_v2_filter_module.c
@@ -1432,6 +1432,9 @@ ngx_http_v2_send_chain(ngx_connection_t 
     size = 0;
 #endif
 
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
+                   "http2 send chain: %p", in);
+
     while (in) {
         size = ngx_buf_size(in->buf);
 
@@ -1450,12 +1453,8 @@ ngx_http_v2_send_chain(ngx_connection_t 
             return NGX_CHAIN_ERROR;
         }
 
-        if (stream->queued) {
-            fc->write->active = 1;
-            fc->write->ready = 0;
-
-        } else {
-            fc->buffered &= ~NGX_HTTP_V2_BUFFERED;
+        if (ngx_http_v2_filter_send(fc, stream) == NGX_ERROR) {
+            return NGX_CHAIN_ERROR;
         }
 
         return NULL;
@@ -1464,9 +1463,16 @@ ngx_http_v2_send_chain(ngx_connection_t 
     h2c = stream->connection;
 
     if (size && ngx_http_v2_flow_control(h2c, stream) == NGX_DECLINED) {
-        fc->write->active = 1;
-        fc->write->ready = 0;
-        return in;
+
+        if (ngx_http_v2_filter_send(fc, stream) == NGX_ERROR) {
+            return NGX_CHAIN_ERROR;
+        }
+
+        if (ngx_http_v2_flow_control(h2c, stream) == NGX_DECLINED) {
+            fc->write->active = 1;
+            fc->write->ready = 0;
+            return in;
+        }
     }
 
     if (in->buf->tag == (ngx_buf_tag_t) &ngx_http_v2_filter_get_shadow) {
@@ -1809,6 +1815,11 @@ ngx_http_v2_waiting_queue(ngx_http_v2_co
 static ngx_inline ngx_int_t
 ngx_http_v2_filter_send(ngx_connection_t *fc, ngx_http_v2_stream_t *stream)
 {
+    if (stream->queued == 0) {
+        fc->buffered &= ~NGX_HTTP_V2_BUFFERED;
+        return NGX_OK;
+    }
+
     stream->blocked = 1;
 
     if (ngx_http_v2_send_output_queue(stream->connection) == NGX_ERROR) {
--- a/src/http/v3/ngx_http_v3_encode.c
+++ b/src/http/v3/ngx_http_v3_encode.c
@@ -157,7 +157,7 @@ ngx_http_v3_encode_field_lri(u_char *p, 
 
     if (data) {
         p2 = p;
-        hlen = ngx_http_v2_huff_encode(data, len, p, 0);
+        hlen = ngx_http_huff_encode(data, len, p, 0);
 
         if (hlen) {
             p = p1;
@@ -199,7 +199,7 @@ ngx_http_v3_encode_field_l(u_char *p, ng
     p = (u_char *) ngx_http_v3_encode_prefix_int(p, name->len, 3);
 
     p2 = p;
-    hlen = ngx_http_v2_huff_encode(name->data, name->len, p, 1);
+    hlen = ngx_http_huff_encode(name->data, name->len, p, 1);
 
     if (hlen) {
         p = p1;
@@ -222,7 +222,7 @@ ngx_http_v3_encode_field_l(u_char *p, ng
     p = (u_char *) ngx_http_v3_encode_prefix_int(p, value->len, 7);
 
     p2 = p;
-    hlen = ngx_http_v2_huff_encode(value->data, value->len, p, 0);
+    hlen = ngx_http_huff_encode(value->data, value->len, p, 0);
 
     if (hlen) {
         p = p1;
@@ -282,7 +282,7 @@ ngx_http_v3_encode_field_lpbi(u_char *p,
 
     if (data) {
         p2 = p;
-        hlen = ngx_http_v2_huff_encode(data, len, p, 0);
+        hlen = ngx_http_huff_encode(data, len, p, 0);
 
         if (hlen) {
             p = p1;
--- a/src/http/v3/ngx_http_v3_parse.c
+++ b/src/http/v3/ngx_http_v3_parse.c
@@ -638,8 +638,8 @@ ngx_http_v3_parse_literal(ngx_connection
             ch = *b->pos++;
 
             if (st->huffman) {
-                if (ngx_http_v2_huff_decode(&st->huffstate, &ch, 1, &st->last,
-                                            st->length == 1, c->log)
+                if (ngx_http_huff_decode(&st->huffstate, &ch, 1, &st->last,
+                                         st->length == 1, c->log)
                     != NGX_OK)
                 {
                     return NGX_ERROR;
--- a/src/os/unix/ngx_freebsd_sendfile_chain.c
+++ b/src/os/unix/ngx_freebsd_sendfile_chain.c
@@ -255,19 +255,6 @@ ngx_freebsd_sendfile_chain(ngx_connectio
 #if (NGX_HAVE_AIO_SENDFILE)
 
         if (ebusy) {
-            if (aio->event.active) {
-                /*
-                 * tolerate duplicate calls; they can happen due to subrequests
-                 * or multiple calls of the next body filter from a filter
-                 */
-
-                if (sent) {
-                    c->busy_count = 0;
-                }
-
-                return in;
-            }
-
             if (sent == 0) {
                 c->busy_count++;
 
--- a/src/os/unix/ngx_linux_sendfile_chain.c
+++ b/src/os/unix/ngx_linux_sendfile_chain.c
@@ -379,15 +379,6 @@ ngx_linux_sendfile_thread(ngx_connection
         return ctx->sent;
     }
 
-    if (task->event.active && ctx->file == file) {
-        /*
-         * tolerate duplicate calls; they can happen due to subrequests
-         * or multiple calls of the next body filter from a filter
-         */
-
-        return NGX_DONE;
-    }
-
     ctx->file = file;
     ctx->socket = c->fd;
     ctx->size = size;
--- a/src/stream/ngx_stream_ssl_module.c
+++ b/src/stream/ngx_stream_ssl_module.c
@@ -269,6 +269,9 @@ static ngx_stream_variable_t  ngx_stream
     { ngx_string("ssl_ciphers"), NULL, ngx_stream_ssl_variable,
       (uintptr_t) ngx_ssl_get_ciphers, NGX_STREAM_VAR_CHANGEABLE, 0 },
 
+    { ngx_string("ssl_curve"), NULL, ngx_stream_ssl_variable,
+      (uintptr_t) ngx_ssl_get_curve, NGX_STREAM_VAR_CHANGEABLE, 0 },
+
     { ngx_string("ssl_curves"), NULL, ngx_stream_ssl_variable,
       (uintptr_t) ngx_ssl_get_curves, NGX_STREAM_VAR_CHANGEABLE, 0 },