Merge branch 'nginx' (nginx-1.23.0).

Change-Id: Ib00b631b91cae593ad6bf5e3768abde319fdc0d5
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
diff --git a/.hgtags b/.hgtags
index 40a7259..ef9cbf7 100644
--- a/.hgtags
+++ b/.hgtags
@@ -467,3 +467,4 @@
 39be8a682c58308d9399cddd57e37f9fdb7bdf3e release-1.21.4
 d986378168fd4d70e0121cabac274c560cca9bdf release-1.21.5
 714eb4b2c09e712fb2572a2164ce2bf67638ccac release-1.21.6
+5da2c0902e8e2aa4534008a582a60c61c135960e release-1.23.0
diff --git a/BUILD b/BUILD
index 4bfe718..053a0b0 100644
--- a/BUILD
+++ b/BUILD
@@ -1,4 +1,4 @@
-# Copyright (C) 2015-2021 Google Inc.
+# Copyright (C) 2015-2022 Google LLC
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -251,6 +251,7 @@
         "src/event/ngx_event_timer.c",
         "src/event/ngx_event_timer.h",
         "src/event/ngx_event_udp.c",
+        "src/event/ngx_event_udp.h",
         "src/os/unix/ngx_alloc.c",
         "src/os/unix/ngx_alloc.h",
         "src/os/unix/ngx_atomic.h",
@@ -1538,5 +1539,5 @@
     preinst = "@nginx_pkgoss//:debian_preinst",
     prerm = "@nginx_pkgoss//:debian_prerm",
     section = "httpd",
-    version = "1.21.6",
+    version = "1.23.0",
 )
diff --git a/LICENSE b/LICENSE
index 41271bf..fd58d5e 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2002-2021 Igor Sysoev
- * Copyright (C) 2011-2021 Nginx, Inc.
- * Copyright (C) 2015-2021 Google Inc.
+ * Copyright (C) 2011-2022 Nginx, Inc.
+ * Copyright (C) 2015-2022 Google LLC
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/README.md b/README.md
index e9d8267..e1e7e9c 100644
--- a/README.md
+++ b/README.md
@@ -22,8 +22,8 @@
 ## License
 
     Copyright (C) 2002-2021 Igor Sysoev
-    Copyright (C) 2011-2021 Nginx, Inc.
-    Copyright (C) 2015-2021 Google Inc.
+    Copyright (C) 2011-2022 Nginx, Inc.
+    Copyright (C) 2015-2022 Google LLC
     All rights reserved.
 
     Redistribution and use in source and binary forms, with or without
diff --git a/WORKSPACE b/WORKSPACE
index 645d13f..243b5ab 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -1,4 +1,4 @@
-# Copyright (C) 2015-2021 Google Inc.
+# Copyright (C) 2015-2022 Google LLC
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/auto/os/conf b/auto/os/conf
index b197ed0..54ed8df 100644
--- a/auto/os/conf
+++ b/auto/os/conf
@@ -110,7 +110,7 @@
         NGX_MACH_CACHE_LINE=64
     ;;
 
-    aarch64 )
+    aarch64 | arm64)
         have=NGX_ALIGNMENT value=16 . $NGX_AUTO/define
         NGX_MACH_CACHE_LINE=64
     ;;
diff --git a/auto/os/linux b/auto/os/linux
index 6519716..f08a772 100644
--- a/auto/os/linux
+++ b/auto/os/linux
@@ -232,4 +232,20 @@
 ngx_include="sys/vfs.h";     . $NGX_AUTO/include
 
 
+# UDP segmentation offloading
+
+ngx_feature="UDP_SEGMENT"
+ngx_feature_name="NGX_HAVE_UDP_SEGMENT"
+ngx_feature_run=no
+ngx_feature_incs="#include <sys/socket.h>
+                  #include <stdint.h>
+                  #include <netinet/udp.h>"
+ngx_feature_path=
+ngx_feature_libs=
+ngx_feature_test="socklen_t optlen = sizeof(int);
+                  int val;
+                  getsockopt(0, SOL_UDP, UDP_SEGMENT, &val, &optlen)"
+. $NGX_AUTO/feature
+
+
 CC_AUX_FLAGS="$cc_aux_flags -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64"
diff --git a/auto/sources b/auto/sources
index 8a0c650..a06071e 100644
--- a/auto/sources
+++ b/auto/sources
@@ -88,7 +88,8 @@
             src/event/ngx_event_timer.h \
             src/event/ngx_event_posted.h \
             src/event/ngx_event_connect.h \
-            src/event/ngx_event_pipe.h"
+            src/event/ngx_event_pipe.h \
+            src/event/ngx_event_udp.h"
 
 EVENT_SRCS="src/event/ngx_event.c \
             src/event/ngx_event_timer.c \
diff --git a/bazel/dependencies.bzl b/bazel/dependencies.bzl
index c67b13f..4bc8485 100644
--- a/bazel/dependencies.bzl
+++ b/bazel/dependencies.bzl
@@ -1,4 +1,4 @@
-# Copyright (C) 2015-2021 Google Inc.
+# Copyright (C) 2015-2022 Google LLC
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/bazel/external/nginx_pkgoss.BUILD b/bazel/external/nginx_pkgoss.BUILD
index 4d8991d..a9b16ed 100755
--- a/bazel/external/nginx_pkgoss.BUILD
+++ b/bazel/external/nginx_pkgoss.BUILD
@@ -1,4 +1,4 @@
-# Copyright (C) 2015-2021 Google Inc.
+# Copyright (C) 2015-2022 Google LLC
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/bazel/external/ngx_brotli.BUILD b/bazel/external/ngx_brotli.BUILD
index ee6a4ac..e6ae660 100755
--- a/bazel/external/ngx_brotli.BUILD
+++ b/bazel/external/ngx_brotli.BUILD
@@ -1,4 +1,4 @@
-# Copyright (C) 2015-2021 Google Inc.
+# Copyright (C) 2015-2022 Google LLC
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/bazel/external/pcre.BUILD b/bazel/external/pcre.BUILD
index 041cd5c..8491cef 100755
--- a/bazel/external/pcre.BUILD
+++ b/bazel/external/pcre.BUILD
@@ -1,4 +1,4 @@
-# Copyright (C) 2015-2021 Google Inc.
+# Copyright (C) 2015-2022 Google LLC
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/bazel/external/zlib.BUILD b/bazel/external/zlib.BUILD
index 0c108e0..f1d0b8d 100755
--- a/bazel/external/zlib.BUILD
+++ b/bazel/external/zlib.BUILD
@@ -1,4 +1,4 @@
-# Copyright (C) 2015-2021 Google Inc.
+# Copyright (C) 2015-2022 Google LLC
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/bazel/nginx.bzl b/bazel/nginx.bzl
index 3105f77..07cfb42 100644
--- a/bazel/nginx.bzl
+++ b/bazel/nginx.bzl
@@ -1,4 +1,4 @@
-# Copyright (C) 2015-2021 Google Inc.
+# Copyright (C) 2015-2022 Google LLC
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/bazel/repositories.bzl b/bazel/repositories.bzl
index 5cff1c0..d6cbf83 100644
--- a/bazel/repositories.bzl
+++ b/bazel/repositories.bzl
@@ -1,4 +1,4 @@
-# Copyright (C) 2015-2021 Google Inc.
+# Copyright (C) 2015-2022 Google LLC
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -34,9 +34,9 @@
     new_git_repository(
         name = "nginx_pkgoss",
         build_file = "@nginx//bazel/external:nginx_pkgoss.BUILD",
-        commit = "aacbbaacab5248f24203b34bcfd09fe69448624d",  # nginx-1.21.6
+        commit = "77f27b3ede2335976a1fb0fff031cf0779a54772",  # nginx-1.23.0
         remote = "https://nginx.googlesource.com/nginx-pkgoss",
-        shallow_since = "1643123831 +0300",
+        shallow_since = "1655830808 +0400",
     )
 
     http_archive(
diff --git a/contrib/vim/syntax/nginx.vim b/contrib/vim/syntax/nginx.vim
index 6828cd3..7d587fc 100644
--- a/contrib/vim/syntax/nginx.vim
+++ b/contrib/vim/syntax/nginx.vim
@@ -111,19 +111,14 @@
 syn keyword ngxDirectiveError contained error_page
 syn keyword ngxDirectiveError contained post_action
 
-syn keyword ngxDirectiveDeprecated contained limit_zone
 syn keyword ngxDirectiveDeprecated contained proxy_downstream_buffer
 syn keyword ngxDirectiveDeprecated contained proxy_upstream_buffer
-syn keyword ngxDirectiveDeprecated contained spdy_chunk_size
-syn keyword ngxDirectiveDeprecated contained spdy_headers_comp
-syn keyword ngxDirectiveDeprecated contained spdy_keepalive_timeout
-syn keyword ngxDirectiveDeprecated contained spdy_max_concurrent_streams
-syn keyword ngxDirectiveDeprecated contained spdy_pool_size
-syn keyword ngxDirectiveDeprecated contained spdy_recv_buffer_size
-syn keyword ngxDirectiveDeprecated contained spdy_recv_timeout
-syn keyword ngxDirectiveDeprecated contained spdy_streams_index_size
 syn keyword ngxDirectiveDeprecated contained ssl
-syn keyword ngxDirectiveDeprecated contained upstream_conf
+syn keyword ngxDirectiveDeprecated contained http2_idle_timeout
+syn keyword ngxDirectiveDeprecated contained http2_max_field_size
+syn keyword ngxDirectiveDeprecated contained http2_max_header_size
+syn keyword ngxDirectiveDeprecated contained http2_max_requests
+syn keyword ngxDirectiveDeprecated contained http2_recv_timeout
 
 syn keyword ngxDirective contained absolute_redirect
 syn keyword ngxDirective contained accept_mutex
@@ -152,6 +147,7 @@
 syn keyword ngxDirective contained auth_jwt
 syn keyword ngxDirective contained auth_jwt_claim_set
 syn keyword ngxDirective contained auth_jwt_header_set
+syn keyword ngxDirective contained auth_jwt_key_cache
 syn keyword ngxDirective contained auth_jwt_key_file
 syn keyword ngxDirective contained auth_jwt_key_request
 syn keyword ngxDirective contained auth_jwt_leeway
@@ -309,17 +305,12 @@
 syn keyword ngxDirective contained hls_mp4_max_buffer_size
 syn keyword ngxDirective contained http2_body_preread_size
 syn keyword ngxDirective contained http2_chunk_size
-syn keyword ngxDirective contained http2_idle_timeout
 syn keyword ngxDirective contained http2_max_concurrent_pushes
 syn keyword ngxDirective contained http2_max_concurrent_streams
-syn keyword ngxDirective contained http2_max_field_size
-syn keyword ngxDirective contained http2_max_header_size
-syn keyword ngxDirective contained http2_max_requests
 syn keyword ngxDirective contained http2_pool_size
 syn keyword ngxDirective contained http2_push
 syn keyword ngxDirective contained http2_push_preload
 syn keyword ngxDirective contained http2_recv_buffer_size
-syn keyword ngxDirective contained http2_recv_timeout
 syn keyword ngxDirective contained http2_streams_index_size
 syn keyword ngxDirective contained if_modified_since
 syn keyword ngxDirective contained ignore_invalid_headers
@@ -339,14 +330,17 @@
 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_buffer_size
 syn keyword ngxDirective contained js_fetch_ciphers
+syn keyword ngxDirective contained js_fetch_max_response_buffer_size
 syn keyword ngxDirective contained js_fetch_protocols
+syn keyword ngxDirective contained js_fetch_timeout
 syn keyword ngxDirective contained js_fetch_trusted_certificate
+syn keyword ngxDirective contained js_fetch_verify
 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
-syn keyword ngxDirective contained js_include
 syn keyword ngxDirective contained js_path
 syn keyword ngxDirective contained js_preread
 syn keyword ngxDirective contained js_set
@@ -391,7 +385,6 @@
 syn keyword ngxDirective contained memcached_bind
 syn keyword ngxDirective contained memcached_buffer_size
 syn keyword ngxDirective contained memcached_connect_timeout
-syn keyword ngxDirective contained memcached_force_ranges
 syn keyword ngxDirective contained memcached_gzip_flag
 syn keyword ngxDirective contained memcached_next_upstream
 syn keyword ngxDirective contained memcached_next_upstream_timeout
@@ -645,7 +638,6 @@
 syn keyword ngxDirective contained status_format
 syn keyword ngxDirective contained status_zone
 syn keyword ngxDirective contained sticky
-syn keyword ngxDirective contained sticky_cookie_insert
 syn keyword ngxDirective contained stub_status
 syn keyword ngxDirective contained sub_filter
 syn keyword ngxDirective contained sub_filter_last_modified
@@ -774,62 +766,14 @@
 syn keyword ngxDirective contained zone_sync_ssl_verify_depth
 syn keyword ngxDirective contained zone_sync_timeout
 
+
 " 3rd party modules list taken from
-" https://github.com/freebsd/freebsd-ports/blob/master/www/nginx-devel/Makefile
-" -----------------------------------------------------------------------------
+" https://github.com/freebsd/freebsd-ports/blob/main/www/nginx-devel/Makefile.extmod
+" ----------------------------------------------------------------------------------
 
-" Accept Language
-" https://github.com/giom/nginx_accept_language_module
-syn keyword ngxDirectiveThirdParty contained set_from_accept_language
-
-" Digest Authentication
-" https://github.com/atomx/nginx-http-auth-digest
-syn keyword ngxDirectiveThirdParty contained auth_digest
-syn keyword ngxDirectiveThirdParty contained auth_digest_drop_time
-syn keyword ngxDirectiveThirdParty contained auth_digest_evasion_time
-syn keyword ngxDirectiveThirdParty contained auth_digest_expires
-syn keyword ngxDirectiveThirdParty contained auth_digest_maxtries
-syn keyword ngxDirectiveThirdParty contained auth_digest_replays
-syn keyword ngxDirectiveThirdParty contained auth_digest_shm_size
-syn keyword ngxDirectiveThirdParty contained auth_digest_timeout
-syn keyword ngxDirectiveThirdParty contained auth_digest_user_file
-
-" SPNEGO Authentication
-" https://github.com/stnoonan/spnego-http-auth-nginx-module
-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
-" https://github.com/kvspb/nginx-auth-ldap
-syn keyword ngxDirectiveThirdParty contained auth_ldap
-syn keyword ngxDirectiveThirdParty contained auth_ldap_cache_enabled
-syn keyword ngxDirectiveThirdParty contained auth_ldap_cache_expiration_time
-syn keyword ngxDirectiveThirdParty contained auth_ldap_cache_size
-syn keyword ngxDirectiveThirdParty contained auth_ldap_servers
-syn keyword ngxDirectiveThirdParty contained auth_ldap_servers_size
-syn keyword ngxDirectiveThirdParty contained ldap_server
-
-" PAM Authentication
-" https://github.com/sto/ngx_http_auth_pam_module
-syn keyword ngxDirectiveThirdParty contained auth_pam
-syn keyword ngxDirectiveThirdParty contained auth_pam_service_name
-syn keyword ngxDirectiveThirdParty contained auth_pam_set_pam_env
-
-" AJP protocol proxy
-" https://github.com/yaoweibin/nginx_ajp_module
-syn keyword ngxDirectiveThirdParty contained ajp_buffers
+" https://github.com/msva/nginx_ajp_module
 syn keyword ngxDirectiveThirdParty contained ajp_buffer_size
+syn keyword ngxDirectiveThirdParty contained ajp_buffers
 syn keyword ngxDirectiveThirdParty contained ajp_busy_buffers_size
 syn keyword ngxDirectiveThirdParty contained ajp_cache
 syn keyword ngxDirectiveThirdParty contained ajp_cache_key
@@ -850,11 +794,13 @@
 syn keyword ngxDirectiveThirdParty contained ajp_max_data_packet_size
 syn keyword ngxDirectiveThirdParty contained ajp_max_temp_file_size
 syn keyword ngxDirectiveThirdParty contained ajp_next_upstream
+syn keyword ngxDirectiveThirdParty contained ajp_param
 syn keyword ngxDirectiveThirdParty contained ajp_pass
 syn keyword ngxDirectiveThirdParty contained ajp_pass_header
 syn keyword ngxDirectiveThirdParty contained ajp_pass_request_body
 syn keyword ngxDirectiveThirdParty contained ajp_pass_request_headers
 syn keyword ngxDirectiveThirdParty contained ajp_read_timeout
+syn keyword ngxDirectiveThirdParty contained ajp_script_url
 syn keyword ngxDirectiveThirdParty contained ajp_secret
 syn keyword ngxDirectiveThirdParty contained ajp_send_lowat
 syn keyword ngxDirectiveThirdParty contained ajp_send_timeout
@@ -865,7 +811,12 @@
 syn keyword ngxDirectiveThirdParty contained ajp_upstream_fail_timeout
 syn keyword ngxDirectiveThirdParty contained ajp_upstream_max_fails
 
-" AWS proxy
+" https://github.com/openresty/array-var-nginx-module
+syn keyword ngxDirectiveThirdParty contained array_join
+syn keyword ngxDirectiveThirdParty contained array_map
+syn keyword ngxDirectiveThirdParty contained array_map_op
+syn keyword ngxDirectiveThirdParty contained array_split
+
 " https://github.com/anomalizer/ngx_aws_auth
 syn keyword ngxDirectiveThirdParty contained aws_access_key
 syn keyword ngxDirectiveThirdParty contained aws_endpoint
@@ -874,7 +825,18 @@
 syn keyword ngxDirectiveThirdParty contained aws_sign
 syn keyword ngxDirectiveThirdParty contained aws_signing_key
 
-" embedding Clojure or Java or Groovy programs
+" https://github.com/google/ngx_brotli
+syn keyword ngxDirectiveThirdParty contained brotli
+syn keyword ngxDirectiveThirdParty contained brotli_buffers
+syn keyword ngxDirectiveThirdParty contained brotli_comp_level
+syn keyword ngxDirectiveThirdParty contained brotli_min_length
+syn keyword ngxDirectiveThirdParty contained brotli_static
+syn keyword ngxDirectiveThirdParty contained brotli_types
+syn keyword ngxDirectiveThirdParty contained brotli_window
+
+" https://github.com/torden/ngx_cache_purge
+syn keyword ngxDirectiveThirdParty contained cache_purge_response_type
+
 " https://github.com/nginx-clojure/nginx-clojure
 syn keyword ngxDirectiveThirdParty contained access_handler_code
 syn keyword ngxDirectiveThirdParty contained access_handler_name
@@ -892,8 +854,8 @@
 syn keyword ngxDirectiveThirdParty contained content_handler_type
 syn keyword ngxDirectiveThirdParty contained handler_code
 syn keyword ngxDirectiveThirdParty contained handler_name
-syn keyword ngxDirectiveThirdParty contained handlers_lazy_init
 syn keyword ngxDirectiveThirdParty contained handler_type
+syn keyword ngxDirectiveThirdParty contained handlers_lazy_init
 syn keyword ngxDirectiveThirdParty contained header_filter_code
 syn keyword ngxDirectiveThirdParty contained header_filter_name
 syn keyword ngxDirectiveThirdParty contained header_filter_property
@@ -921,18 +883,20 @@
 syn keyword ngxDirectiveThirdParty contained shared_map
 syn keyword ngxDirectiveThirdParty contained write_page_size
 
+" https://github.com/AirisX/nginx_cookie_flag_module
+syn keyword ngxDirectiveThirdParty contained set_cookie_flag
 
-" Certificate Transparency
 " https://github.com/grahamedgecombe/nginx-ct
 syn keyword ngxDirectiveThirdParty contained ssl_ct
 syn keyword ngxDirectiveThirdParty contained ssl_ct_static_scts
 
-" ngx_echo
 " https://github.com/openresty/echo-nginx-module
+syn keyword ngxDirectiveThirdParty contained echo
 syn keyword ngxDirectiveThirdParty contained echo_abort_parent
 syn keyword ngxDirectiveThirdParty contained echo_after_body
 syn keyword ngxDirectiveThirdParty contained echo_before_body
 syn keyword ngxDirectiveThirdParty contained echo_blocking_sleep
+syn keyword ngxDirectiveThirdParty contained echo_duplicate
 syn keyword ngxDirectiveThirdParty contained echo_end
 syn keyword ngxDirectiveThirdParty contained echo_exec
 syn keyword ngxDirectiveThirdParty contained echo_flush
@@ -942,28 +906,124 @@
 syn keyword ngxDirectiveThirdParty contained echo_read_request_body
 syn keyword ngxDirectiveThirdParty contained echo_request_body
 syn keyword ngxDirectiveThirdParty contained echo_reset_timer
+syn keyword ngxDirectiveThirdParty contained echo_sleep
 syn keyword ngxDirectiveThirdParty contained echo_status
 syn keyword ngxDirectiveThirdParty contained echo_subrequest
 syn keyword ngxDirectiveThirdParty contained echo_subrequest_async
 
-" FastDFS
-" https://github.com/happyfish100/fastdfs-nginx-module
-syn keyword ngxDirectiveThirdParty contained ngx_fastdfs_module
+" https://github.com/openresty/drizzle-nginx-module
+syn keyword ngxDirectiveThirdParty contained drizzle_buffer_size
+syn keyword ngxDirectiveThirdParty contained drizzle_connect_timeout
+syn keyword ngxDirectiveThirdParty contained drizzle_dbname
+syn keyword ngxDirectiveThirdParty contained drizzle_keepalive
+syn keyword ngxDirectiveThirdParty contained drizzle_module_header
+syn keyword ngxDirectiveThirdParty contained drizzle_pass
+syn keyword ngxDirectiveThirdParty contained drizzle_query
+syn keyword ngxDirectiveThirdParty contained drizzle_recv_cols_timeout
+syn keyword ngxDirectiveThirdParty contained drizzle_recv_rows_timeout
+syn keyword ngxDirectiveThirdParty contained drizzle_send_query_timeout
+syn keyword ngxDirectiveThirdParty contained drizzle_server
+syn keyword ngxDirectiveThirdParty contained drizzle_status
 
-" ngx_headers_more
+" https://github.com/ZigzagAK/ngx_dynamic_upstream
+syn keyword ngxDirectiveThirdParty contained dns_add_down
+syn keyword ngxDirectiveThirdParty contained dns_ipv6
+syn keyword ngxDirectiveThirdParty contained dns_update
+syn keyword ngxDirectiveThirdParty contained dynamic_state_file
+syn keyword ngxDirectiveThirdParty contained dynamic_upstream
+
+" https://github.com/ZigzagAK/ngx_dynamic_healthcheck
+syn keyword ngxDirectiveThirdParty contained check
+syn keyword ngxDirectiveThirdParty contained check_disable_host
+syn keyword ngxDirectiveThirdParty contained check_exclude_host
+syn keyword ngxDirectiveThirdParty contained check_persistent
+syn keyword ngxDirectiveThirdParty contained check_request_body
+syn keyword ngxDirectiveThirdParty contained check_request_headers
+syn keyword ngxDirectiveThirdParty contained check_request_uri
+syn keyword ngxDirectiveThirdParty contained check_response_body
+syn keyword ngxDirectiveThirdParty contained check_response_codes
+syn keyword ngxDirectiveThirdParty contained healthcheck
+syn keyword ngxDirectiveThirdParty contained healthcheck_buffer_size
+syn keyword ngxDirectiveThirdParty contained healthcheck_disable_host
+syn keyword ngxDirectiveThirdParty contained healthcheck_get
+syn keyword ngxDirectiveThirdParty contained healthcheck_persistent
+syn keyword ngxDirectiveThirdParty contained healthcheck_request_body
+syn keyword ngxDirectiveThirdParty contained healthcheck_request_headers
+syn keyword ngxDirectiveThirdParty contained healthcheck_request_uri
+syn keyword ngxDirectiveThirdParty contained healthcheck_response_body
+syn keyword ngxDirectiveThirdParty contained healthcheck_response_codes
+syn keyword ngxDirectiveThirdParty contained healthcheck_status
+syn keyword ngxDirectiveThirdParty contained healthcheck_update
+
+" https://github.com/openresty/encrypted-session-nginx-module
+syn keyword ngxDirectiveThirdParty contained encrypted_session_expires
+syn keyword ngxDirectiveThirdParty contained encrypted_session_iv
+syn keyword ngxDirectiveThirdParty contained encrypted_session_key
+syn keyword ngxDirectiveThirdParty contained set_decrypt_session
+syn keyword ngxDirectiveThirdParty contained set_encrypt_session
+
+" https://github.com/calio/form-input-nginx-module
+syn keyword ngxDirectiveThirdParty contained set_form_input
+syn keyword ngxDirectiveThirdParty contained set_form_input_multi
+
+" https://github.com/nieoding/nginx-gridfs
+syn keyword ngxDirectiveThirdParty contained gridfs
+syn keyword ngxDirectiveThirdParty contained mongo
+
 " https://github.com/openresty/headers-more-nginx-module
 syn keyword ngxDirectiveThirdParty contained more_clear_headers
 syn keyword ngxDirectiveThirdParty contained more_clear_input_headers
 syn keyword ngxDirectiveThirdParty contained more_set_headers
 syn keyword ngxDirectiveThirdParty contained more_set_input_headers
 
-" NGINX WebDAV missing commands support (PROPFIND & OPTIONS)
+" https://github.com/dvershinin/nginx_accept_language_module
+syn keyword ngxDirectiveThirdParty contained set_from_accept_language
+
+" https://github.com/atomx/nginx-http-auth-digest
+syn keyword ngxDirectiveThirdParty contained auth_digest
+syn keyword ngxDirectiveThirdParty contained auth_digest_drop_time
+syn keyword ngxDirectiveThirdParty contained auth_digest_evasion_time
+syn keyword ngxDirectiveThirdParty contained auth_digest_expires
+syn keyword ngxDirectiveThirdParty contained auth_digest_maxtries
+syn keyword ngxDirectiveThirdParty contained auth_digest_replays
+syn keyword ngxDirectiveThirdParty contained auth_digest_shm_size
+syn keyword ngxDirectiveThirdParty contained auth_digest_timeout
+syn keyword ngxDirectiveThirdParty contained auth_digest_user_file
+
+" https://github.com/stnoonan/spnego-http-auth-nginx-module
+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
+
+" https://github.com/kvspb/nginx-auth-ldap
+syn keyword ngxDirectiveThirdParty contained auth_ldap
+syn keyword ngxDirectiveThirdParty contained auth_ldap_cache_enabled
+syn keyword ngxDirectiveThirdParty contained auth_ldap_cache_expiration_time
+syn keyword ngxDirectiveThirdParty contained auth_ldap_cache_size
+syn keyword ngxDirectiveThirdParty contained auth_ldap_servers
+syn keyword ngxDirectiveThirdParty contained auth_ldap_servers_size
+syn keyword ngxDirectiveThirdParty contained ldap_server
+
+" https://github.com/sto/ngx_http_auth_pam_module
+syn keyword ngxDirectiveThirdParty contained auth_pam
+syn keyword ngxDirectiveThirdParty contained auth_pam_service_name
+syn keyword ngxDirectiveThirdParty contained auth_pam_set_pam_env
+
 " https://github.com/arut/nginx-dav-ext-module
 syn keyword ngxDirectiveThirdParty contained dav_ext_lock
 syn keyword ngxDirectiveThirdParty contained dav_ext_lock_zone
 syn keyword ngxDirectiveThirdParty contained dav_ext_methods
 
-" ngx_eval
 " https://github.com/openresty/nginx-eval-module
 syn keyword ngxDirectiveThirdParty contained eval
 syn keyword ngxDirectiveThirdParty contained eval_buffer_size
@@ -971,7 +1031,6 @@
 syn keyword ngxDirectiveThirdParty contained eval_override_content_type
 syn keyword ngxDirectiveThirdParty contained eval_subrequest_in_memory
 
-" Fancy Index
 " https://github.com/aperezdc/ngx-fancyindex
 syn keyword ngxDirectiveThirdParty contained fancyindex
 syn keyword ngxDirectiveThirdParty contained fancyindex_css_href
@@ -988,40 +1047,29 @@
 syn keyword ngxDirectiveThirdParty contained fancyindex_show_path
 syn keyword ngxDirectiveThirdParty contained fancyindex_time_format
 
-" Footer filter
 " https://github.com/alibaba/nginx-http-footer-filter
 syn keyword ngxDirectiveThirdParty contained footer
 syn keyword ngxDirectiveThirdParty contained footer_types
 
-" ngx_http_geoip2_module
 " https://github.com/leev/ngx_http_geoip2_module
 syn keyword ngxDirectiveThirdParty contained geoip2
 syn keyword ngxDirectiveThirdParty contained geoip2_proxy
 syn keyword ngxDirectiveThirdParty contained geoip2_proxy_recursive
 
-" A version of the Nginx HTTP stub status module that outputs in JSON format
-" https://github.com/nginx-modules/nginx-json-status-module
-syn keyword ngxDirectiveThirdParty contained json_status
-syn keyword ngxDirectiveThirdParty contained json_status_type
+" https://github.com/ip2location/ip2location-nginx
+syn keyword ngxDirectiveThirdParty contained ip2location_database
+syn keyword ngxDirectiveThirdParty contained ip2location_proxy
+syn keyword ngxDirectiveThirdParty contained ip2location_proxy_recursive
 
-" MogileFS client for nginx
-" https://github.com/vkholodkov/nginx-mogilefs-module
-syn keyword ngxDirectiveThirdParty contained mogilefs_class
-syn keyword ngxDirectiveThirdParty contained mogilefs_connect_timeout
-syn keyword ngxDirectiveThirdParty contained mogilefs_domain
-syn keyword ngxDirectiveThirdParty contained mogilefs_methods
-syn keyword ngxDirectiveThirdParty contained mogilefs_noverify
-syn keyword ngxDirectiveThirdParty contained mogilefs_pass
-syn keyword ngxDirectiveThirdParty contained mogilefs_read_timeout
-syn keyword ngxDirectiveThirdParty contained mogilefs_send_timeout
-syn keyword ngxDirectiveThirdParty contained mogilefs_tracker
+" https://github.com/ip2location/ip2proxy-nginx
+syn keyword ngxDirectiveThirdParty contained ip2proxy_database
+syn keyword ngxDirectiveThirdParty contained ip2proxy_proxy
+syn keyword ngxDirectiveThirdParty contained ip2proxy_proxy_recursive
 
-" Ancient nginx plugin; probably not useful to anyone
 " https://github.com/kr/nginx-notice
 syn keyword ngxDirectiveThirdParty contained notice
 syn keyword ngxDirectiveThirdParty contained notice_type
 
-" nchan
 " https://github.com/slact/nchan
 syn keyword ngxDirectiveThirdParty contained nchan_access_control_allow_credentials
 syn keyword ngxDirectiveThirdParty contained nchan_access_control_allow_origin
@@ -1034,8 +1082,8 @@
 syn keyword ngxDirectiveThirdParty contained nchan_benchmark_subscriber_distribution
 syn keyword ngxDirectiveThirdParty contained nchan_benchmark_subscribers_per_channel
 syn keyword ngxDirectiveThirdParty contained nchan_benchmark_time
-syn keyword ngxDirectiveThirdParty contained nchan_channel_events_channel_id
 syn keyword ngxDirectiveThirdParty contained nchan_channel_event_string
+syn keyword ngxDirectiveThirdParty contained nchan_channel_events_channel_id
 syn keyword ngxDirectiveThirdParty contained nchan_channel_group
 syn keyword ngxDirectiveThirdParty contained nchan_channel_group_accounting
 syn keyword ngxDirectiveThirdParty contained nchan_channel_id
@@ -1074,11 +1122,25 @@
 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_cluster_check_interval_backoff
+syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_check_interval_jitter
+syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_check_interval_max
+syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_check_interval_min
+syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_connect_timeout
+syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_max_failing_time
+syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_recovery_delay
+syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_recovery_delay_backoff
+syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_recovery_delay_jitter
+syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_recovery_delay_max
+syn keyword ngxDirectiveThirdParty contained nchan_redis_cluster_recovery_delay_min
+syn keyword ngxDirectiveThirdParty contained nchan_redis_command_timeout
 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_load_scripts_unconditionally
 syn keyword ngxDirectiveThirdParty contained nchan_redis_namespace
+syn keyword ngxDirectiveThirdParty contained nchan_redis_node_connect_timeout
 syn keyword ngxDirectiveThirdParty contained nchan_redis_nostore_fastpublish
 syn keyword ngxDirectiveThirdParty contained nchan_redis_optimize_target
 syn keyword ngxDirectiveThirdParty contained nchan_redis_pass
@@ -1086,6 +1148,13 @@
 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_reconnect_delay
+syn keyword ngxDirectiveThirdParty contained nchan_redis_reconnect_delay_backoff
+syn keyword ngxDirectiveThirdParty contained nchan_redis_reconnect_delay_jitter
+syn keyword ngxDirectiveThirdParty contained nchan_redis_reconnect_delay_max
+syn keyword ngxDirectiveThirdParty contained nchan_redis_reconnect_delay_min
+syn keyword ngxDirectiveThirdParty contained nchan_redis_retry_commands
+syn keyword ngxDirectiveThirdParty contained nchan_redis_retry_commands_max_wait
 syn keyword ngxDirectiveThirdParty contained nchan_redis_server
 syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl
 syn keyword ngxDirectiveThirdParty contained nchan_redis_ssl_ciphers
@@ -1113,10 +1182,10 @@
 syn keyword ngxDirectiveThirdParty contained nchan_stub_status
 syn keyword ngxDirectiveThirdParty contained nchan_sub_channel_id
 syn keyword ngxDirectiveThirdParty contained nchan_subscribe_existing_channels_only
+syn keyword ngxDirectiveThirdParty contained nchan_subscribe_request
 syn keyword ngxDirectiveThirdParty contained nchan_subscriber
 syn keyword ngxDirectiveThirdParty contained nchan_subscriber_channel_id
 syn keyword ngxDirectiveThirdParty contained nchan_subscriber_compound_etag_message_id
-syn keyword ngxDirectiveThirdParty contained nchan_subscribe_request
 syn keyword ngxDirectiveThirdParty contained nchan_subscriber_first_message
 syn keyword ngxDirectiveThirdParty contained nchan_subscriber_http_raw_stream_separator
 syn keyword ngxDirectiveThirdParty contained nchan_subscriber_info
@@ -1145,7 +1214,6 @@
 syn keyword ngxDirectiveThirdParty contained push_subscriber_concurrency
 syn keyword ngxDirectiveThirdParty contained push_subscriber_timeout
 
-" Push Stream
 " https://github.com/wandenberg/nginx-push-stream-module
 syn keyword ngxDirectiveThirdParty contained push_stream_allow_connections_to_events_channel
 syn keyword ngxDirectiveThirdParty contained push_stream_allowed_origins
@@ -1184,23 +1252,6 @@
 syn keyword ngxDirectiveThirdParty contained push_stream_wildcard_channel_max_qtd
 syn keyword ngxDirectiveThirdParty contained push_stream_wildcard_channel_prefix
 
-" redis module
-" https://www.nginx.com/resources/wiki/modules/redis/
-syn keyword ngxDirectiveThirdParty contained redis_bind
-syn keyword ngxDirectiveThirdParty contained redis_buffer_size
-syn keyword ngxDirectiveThirdParty contained redis_connect_timeout
-syn keyword ngxDirectiveThirdParty contained redis_gzip_flag
-syn keyword ngxDirectiveThirdParty contained redis_next_upstream
-syn keyword ngxDirectiveThirdParty contained redis_pass
-syn keyword ngxDirectiveThirdParty contained redis_read_timeout
-syn keyword ngxDirectiveThirdParty contained redis_send_timeout
-
-" ngx_http_response
-" http://catap.ru/downloads/nginx/
-syn keyword ngxDirectiveThirdParty contained response
-syn keyword ngxDirectiveThirdParty contained response_type
-
-" nginx_substitutions_filter
 " https://github.com/yaoweibin/ngx_http_substitutions_filter_module
 syn keyword ngxDirectiveThirdParty contained subs_buffers
 syn keyword ngxDirectiveThirdParty contained subs_filter
@@ -1208,7 +1259,6 @@
 syn keyword ngxDirectiveThirdParty contained subs_filter_types
 syn keyword ngxDirectiveThirdParty contained subs_line_buffer_size
 
-" Tarantool nginx upstream module
 " https://github.com/tarantool/nginx_upstream_module
 syn keyword ngxDirectiveThirdParty contained tnt_allowed_indexes
 syn keyword ngxDirectiveThirdParty contained tnt_allowed_spaces
@@ -1238,44 +1288,28 @@
 syn keyword ngxDirectiveThirdParty contained tnt_update
 syn keyword ngxDirectiveThirdParty contained tnt_upsert
 
-" A module for nginx web server for handling file uploads using multipart/form-data encoding (RFC 1867)
-" https://github.com/Austinb/nginx-upload-module
+" https://github.com/fdintino/nginx-upload-module
+syn keyword ngxDirectiveThirdParty contained upload_add_header
 syn keyword ngxDirectiveThirdParty contained upload_aggregate_form_field
-syn keyword ngxDirectiveThirdParty contained upload_archive_elm
-syn keyword ngxDirectiveThirdParty contained upload_archive_elm_separator
-syn keyword ngxDirectiveThirdParty contained upload_archive_path
-syn keyword ngxDirectiveThirdParty contained upload_archive_path_separator
 syn keyword ngxDirectiveThirdParty contained upload_buffer_size
 syn keyword ngxDirectiveThirdParty contained upload_cleanup
-syn keyword ngxDirectiveThirdParty contained upload_content_type
-syn keyword ngxDirectiveThirdParty contained upload_discard
-syn keyword ngxDirectiveThirdParty contained upload_field_name
-syn keyword ngxDirectiveThirdParty contained upload_file_crc32
-syn keyword ngxDirectiveThirdParty contained upload_file_md5
-syn keyword ngxDirectiveThirdParty contained upload_file_md5_uc
-syn keyword ngxDirectiveThirdParty contained upload_file_name
-syn keyword ngxDirectiveThirdParty contained upload_file_sha1
-syn keyword ngxDirectiveThirdParty contained upload_file_sha1_uc
-syn keyword ngxDirectiveThirdParty contained upload_file_size
-syn keyword ngxDirectiveThirdParty contained upload_filter
+syn keyword ngxDirectiveThirdParty contained upload_empty_fiels_names
+syn keyword ngxDirectiveThirdParty contained upload_limit_rate
 syn keyword ngxDirectiveThirdParty contained upload_max_file_size
 syn keyword ngxDirectiveThirdParty contained upload_max_output_body_len
 syn keyword ngxDirectiveThirdParty contained upload_max_part_header_len
+syn keyword ngxDirectiveThirdParty contained upload_merge_buffer_size
 syn keyword ngxDirectiveThirdParty contained upload_pass
 syn keyword ngxDirectiveThirdParty contained upload_pass_args
 syn keyword ngxDirectiveThirdParty contained upload_pass_form_field
+syn keyword ngxDirectiveThirdParty contained upload_range_header_buffer_size
+syn keyword ngxDirectiveThirdParty contained upload_resumable
 syn keyword ngxDirectiveThirdParty contained upload_set_form_field
+syn keyword ngxDirectiveThirdParty contained upload_state_store
 syn keyword ngxDirectiveThirdParty contained upload_store
 syn keyword ngxDirectiveThirdParty contained upload_store_access
-syn keyword ngxDirectiveThirdParty contained upload_tmp_path
-syn keyword ngxDirectiveThirdParty contained upload_unzip
-syn keyword ngxDirectiveThirdParty contained upload_unzip_buffers
-syn keyword ngxDirectiveThirdParty contained upload_unzip_hash
-syn keyword ngxDirectiveThirdParty contained upload_unzip_max_file_name_len
-syn keyword ngxDirectiveThirdParty contained upload_unzip_window
-syn keyword ngxDirectiveThirdParty contained upload_void_content_type
+syn keyword ngxDirectiveThirdParty contained upload_tame_arrays
 
-" nginx-upload-progress-module
 " https://github.com/masterzen/nginx-upload-progress-module
 syn keyword ngxDirectiveThirdParty contained report_uploads
 syn keyword ngxDirectiveThirdParty contained track_uploads
@@ -1288,9 +1322,7 @@
 syn keyword ngxDirectiveThirdParty contained upload_progress_jsonp_parameter
 syn keyword ngxDirectiveThirdParty contained upload_progress_template
 
-" Health checks upstreams for nginx
 " https://github.com/yaoweibin/nginx_upstream_check_module
-syn keyword ngxDirectiveThirdParty contained check
 syn keyword ngxDirectiveThirdParty contained check_fastcgi_param
 syn keyword ngxDirectiveThirdParty contained check_http_expect_alive
 syn keyword ngxDirectiveThirdParty contained check_http_send
@@ -1298,13 +1330,14 @@
 syn keyword ngxDirectiveThirdParty contained check_shm_size
 syn keyword ngxDirectiveThirdParty contained check_status
 
-" The fair load balancer module for nginx
-" https://github.com/cryptofuture/nginx-upstream-fair
+" https://github.com/jaygooby/nginx-upstream-fair
 syn keyword ngxDirectiveThirdParty contained fair
 syn keyword ngxDirectiveThirdParty contained upstream_fair_shm_size
 
-" Nginx Video Thumb Extractor Module
-" https://github.com/wandenberg/nginx-video-thumbextractor-module
+" https://github.com/ayty-adrianomartins/nginx-sticky-module-ng
+syn keyword ngxDirectiveThirdParty contained sticky_no_fallback
+
+" https://github.com/Novetta/nginx-video-thumbextractor-module
 syn keyword ngxDirectiveThirdParty contained video_thumbextractor
 syn keyword ngxDirectiveThirdParty contained video_thumbextractor_image_height
 syn keyword ngxDirectiveThirdParty contained video_thumbextractor_image_width
@@ -1329,43 +1362,14 @@
 syn keyword ngxDirectiveThirdParty contained video_thumbextractor_video_filename
 syn keyword ngxDirectiveThirdParty contained video_thumbextractor_video_second
 
-" drizzle-nginx-module - Upstream module for talking to MySQL and Drizzle directly
-" https://github.com/openresty/drizzle-nginx-module
-syn keyword ngxDirectiveThirdParty contained drizzle_buffer_size
-syn keyword ngxDirectiveThirdParty contained drizzle_connect_timeout
-syn keyword ngxDirectiveThirdParty contained drizzle_dbname
-syn keyword ngxDirectiveThirdParty contained drizzle_keepalive
-syn keyword ngxDirectiveThirdParty contained drizzle_module_header
-syn keyword ngxDirectiveThirdParty contained drizzle_pass
-syn keyword ngxDirectiveThirdParty contained drizzle_query
-syn keyword ngxDirectiveThirdParty contained drizzle_recv_cols_timeout
-syn keyword ngxDirectiveThirdParty contained drizzle_recv_rows_timeout
-syn keyword ngxDirectiveThirdParty contained drizzle_send_query_timeout
-syn keyword ngxDirectiveThirdParty contained drizzle_server
-syn keyword ngxDirectiveThirdParty contained drizzle_status
+" https://github.com/calio/iconv-nginx-module
+syn keyword ngxDirectiveThirdParty contained iconv_buffer_size
+syn keyword ngxDirectiveThirdParty contained iconv_filter
+syn keyword ngxDirectiveThirdParty contained set_iconv
 
-" ngx_dynamic_upstream
-" https://github.com/cubicdaiya/ngx_dynamic_upstream
-syn keyword ngxDirectiveThirdParty contained dynamic_upstream
-
-" encrypt and decrypt nginx variable values
-" https://github.com/openresty/encrypted-session-nginx-module
-syn keyword ngxDirectiveThirdParty contained encrypted_session_expires
-syn keyword ngxDirectiveThirdParty contained encrypted_session_iv
-syn keyword ngxDirectiveThirdParty contained encrypted_session_key
-syn keyword ngxDirectiveThirdParty contained set_decrypt_session
-syn keyword ngxDirectiveThirdParty contained set_encrypt_session
-
-" serve content directly from MongoDB's GridFS
-" https://github.com/mdirolf/nginx-gridfs
-syn keyword ngxDirectiveThirdParty contained gridfs
-syn keyword ngxDirectiveThirdParty contained mongo
-
-" Adds support for arithmetic operations to NGINX config
-" https://github.com/arut/nginx-let-module
+" https://github.com/baysao/nginx-let-module
 syn keyword ngxDirectiveThirdParty contained let
 
-" ngx_http_lua_module - Embed the power of Lua into Nginx HTTP Servers
 " https://github.com/openresty/lua-nginx-module
 syn keyword ngxDirectiveThirdParty contained access_by_lua
 syn keyword ngxDirectiveThirdParty contained access_by_lua_block
@@ -1431,6 +1435,8 @@
 syn keyword ngxDirectiveThirdParty contained rewrite_by_lua_block
 syn keyword ngxDirectiveThirdParty contained rewrite_by_lua_file
 syn keyword ngxDirectiveThirdParty contained rewrite_by_lua_no_postpone
+syn keyword ngxDirectiveThirdParty contained server_rewrite_by_lua_block
+syn keyword ngxDirectiveThirdParty contained server_rewrite_by_lua_file
 syn keyword ngxDirectiveThirdParty contained set_by_lua
 syn keyword ngxDirectiveThirdParty contained set_by_lua_block
 syn keyword ngxDirectiveThirdParty contained set_by_lua_file
@@ -1443,7 +1449,16 @@
 syn keyword ngxDirectiveThirdParty contained ssl_session_store_by_lua_block
 syn keyword ngxDirectiveThirdParty contained ssl_session_store_by_lua_file
 
-" ngx_memc - An extended version of the standard memcached module
+" https://github.com/Taymindis/nginx-link-function
+syn keyword ngxDirectiveThirdParty contained ngx_link_func_add_prop
+syn keyword ngxDirectiveThirdParty contained ngx_link_func_add_req_header
+syn keyword ngxDirectiveThirdParty contained ngx_link_func_ca_cert
+syn keyword ngxDirectiveThirdParty contained ngx_link_func_call
+syn keyword ngxDirectiveThirdParty contained ngx_link_func_download_link_lib
+syn keyword ngxDirectiveThirdParty contained ngx_link_func_lib
+syn keyword ngxDirectiveThirdParty contained ngx_link_func_shm_size
+syn keyword ngxDirectiveThirdParty contained ngx_link_func_subrequest
+
 " https://github.com/openresty/memc-nginx-module
 syn keyword ngxDirectiveThirdParty contained memc_buffer_size
 syn keyword ngxDirectiveThirdParty contained memc_cmds_allowed
@@ -1457,21 +1472,24 @@
 syn keyword ngxDirectiveThirdParty contained memc_upstream_fail_timeout
 syn keyword ngxDirectiveThirdParty contained memc_upstream_max_fails
 
-" ModSecurity web application firewall
-" https://github.com/SpiderLabs/ModSecurity/tree/master
-syn keyword ngxDirectiveThirdParty contained ModSecurityConfig
-syn keyword ngxDirectiveThirdParty contained ModSecurityEnabled
-syn keyword ngxDirectiveThirdParty contained pool_context_hash_size
+" https://github.com/SpiderLabs/ModSecurity-nginx
+syn keyword ngxDirectiveThirdParty contained modsecurity
+syn keyword ngxDirectiveThirdParty contained modsecurity_rules
+syn keyword ngxDirectiveThirdParty contained modsecurity_rules_file
+syn keyword ngxDirectiveThirdParty contained modsecurity_rules_remote
+syn keyword ngxDirectiveThirdParty contained modsecurity_transaction_id
 
-" NAXSI is an open-source, high performance, low rules maintenance WAF for NGINX
 " https://github.com/nbs-system/naxsi
 syn keyword ngxDirectiveThirdParty contained BasicRule
 syn keyword ngxDirectiveThirdParty contained CheckRule
 syn keyword ngxDirectiveThirdParty contained DeniedUrl
+syn keyword ngxDirectiveThirdParty contained IgnoreCIDR
+syn keyword ngxDirectiveThirdParty contained IgnoreIP
 syn keyword ngxDirectiveThirdParty contained LearningMode
 syn keyword ngxDirectiveThirdParty contained LibInjectionSql
 syn keyword ngxDirectiveThirdParty contained LibInjectionXss
 syn keyword ngxDirectiveThirdParty contained MainRule
+syn keyword ngxDirectiveThirdParty contained NaxsiLogFile
 syn keyword ngxDirectiveThirdParty contained SecRulesDisabled
 syn keyword ngxDirectiveThirdParty contained SecRulesEnabled
 syn keyword ngxDirectiveThirdParty contained basic_rule
@@ -1481,17 +1499,31 @@
 syn keyword ngxDirectiveThirdParty contained libinjection_sql
 syn keyword ngxDirectiveThirdParty contained libinjection_xss
 syn keyword ngxDirectiveThirdParty contained main_rule
+syn keyword ngxDirectiveThirdParty contained naxsi_log
 syn keyword ngxDirectiveThirdParty contained rules_disabled
 syn keyword ngxDirectiveThirdParty contained rules_enabled
 
-" Phusion Passenger
-" https://www.phusionpassenger.com/library/config/nginx/reference/
+" https://github.com/opentracing-contrib/nginx-opentracing
+syn keyword ngxDirectiveThirdParty contained opentracing
+syn keyword ngxDirectiveThirdParty contained opentracing_fastcgi_propagate_context
+syn keyword ngxDirectiveThirdParty contained opentracing_grpc_propagate_context
+syn keyword ngxDirectiveThirdParty contained opentracing_load_tracer
+syn keyword ngxDirectiveThirdParty contained opentracing_location_operation_name
+syn keyword ngxDirectiveThirdParty contained opentracing_operation_name
+syn keyword ngxDirectiveThirdParty contained opentracing_propagate_context
+syn keyword ngxDirectiveThirdParty contained opentracing_tag
+syn keyword ngxDirectiveThirdParty contained opentracing_trace_locations
+syn keyword ngxDirectiveThirdParty contained opentracing_trust_incoming_span
+
+" https://github.com/phusion/passenger
 syn keyword ngxDirectiveThirdParty contained passenger_abort_on_startup_error
 syn keyword ngxDirectiveThirdParty contained passenger_abort_websockets_on_process_shutdown
 syn keyword ngxDirectiveThirdParty contained passenger_admin_panel_auth_type
 syn keyword ngxDirectiveThirdParty contained passenger_admin_panel_password
 syn keyword ngxDirectiveThirdParty contained passenger_admin_panel_url
 syn keyword ngxDirectiveThirdParty contained passenger_admin_panel_username
+syn keyword ngxDirectiveThirdParty contained passenger_analytics_log_group
+syn keyword ngxDirectiveThirdParty contained passenger_analytics_log_user
 syn keyword ngxDirectiveThirdParty contained passenger_anonymous_telemetry_proxy
 syn keyword ngxDirectiveThirdParty contained passenger_app_env
 syn keyword ngxDirectiveThirdParty contained passenger_app_file_descriptor_ulimit
@@ -1499,20 +1531,25 @@
 syn keyword ngxDirectiveThirdParty contained passenger_app_log_file
 syn keyword ngxDirectiveThirdParty contained passenger_app_rights
 syn keyword ngxDirectiveThirdParty contained passenger_app_root
+syn keyword ngxDirectiveThirdParty contained passenger_app_start_command
 syn keyword ngxDirectiveThirdParty contained passenger_app_type
 syn keyword ngxDirectiveThirdParty contained passenger_base_uri
 syn keyword ngxDirectiveThirdParty contained passenger_buffer_response
 syn keyword ngxDirectiveThirdParty contained passenger_buffer_size
+syn keyword ngxDirectiveThirdParty contained passenger_buffer_upload
 syn keyword ngxDirectiveThirdParty contained passenger_buffers
 syn keyword ngxDirectiveThirdParty contained passenger_busy_buffers_size
 syn keyword ngxDirectiveThirdParty contained passenger_concurrency_model
 syn keyword ngxDirectiveThirdParty contained passenger_core_file_descriptor_ulimit
 syn keyword ngxDirectiveThirdParty contained passenger_ctl
 syn keyword ngxDirectiveThirdParty contained passenger_data_buffer_dir
+syn keyword ngxDirectiveThirdParty contained passenger_debug_log_file
 syn keyword ngxDirectiveThirdParty contained passenger_debugger
 syn keyword ngxDirectiveThirdParty contained passenger_default_group
 syn keyword ngxDirectiveThirdParty contained passenger_default_user
+syn keyword ngxDirectiveThirdParty contained passenger_direct_instance_request_address
 syn keyword ngxDirectiveThirdParty contained passenger_disable_anonymous_telemetry
+syn keyword ngxDirectiveThirdParty contained passenger_disable_log_prefix
 syn keyword ngxDirectiveThirdParty contained passenger_disable_security_update_check
 syn keyword ngxDirectiveThirdParty contained passenger_document_root
 syn keyword ngxDirectiveThirdParty contained passenger_dump_config_manifest
@@ -1548,8 +1585,10 @@
 syn keyword ngxDirectiveThirdParty contained passenger_pass_header
 syn keyword ngxDirectiveThirdParty contained passenger_pool_idle_time
 syn keyword ngxDirectiveThirdParty contained passenger_pre_start
+syn keyword ngxDirectiveThirdParty contained passenger_preload_bundler
 syn keyword ngxDirectiveThirdParty contained passenger_python
 syn keyword ngxDirectiveThirdParty contained passenger_read_timeout
+syn keyword ngxDirectiveThirdParty contained passenger_request_buffering
 syn keyword ngxDirectiveThirdParty contained passenger_request_queue_overflow_status_code
 syn keyword ngxDirectiveThirdParty contained passenger_resist_deployment_errors
 syn keyword ngxDirectiveThirdParty contained passenger_response_buffer_high_watermark
@@ -1561,36 +1600,36 @@
 syn keyword ngxDirectiveThirdParty contained passenger_set_header
 syn keyword ngxDirectiveThirdParty contained passenger_show_version_in_header
 syn keyword ngxDirectiveThirdParty contained passenger_socket_backlog
+syn keyword ngxDirectiveThirdParty contained passenger_spawn_dir
+syn keyword ngxDirectiveThirdParty contained passenger_spawn_exception_status_code
 syn keyword ngxDirectiveThirdParty contained passenger_spawn_method
 syn keyword ngxDirectiveThirdParty contained passenger_start_timeout
 syn keyword ngxDirectiveThirdParty contained passenger_startup_file
 syn keyword ngxDirectiveThirdParty contained passenger_stat_throttle_rate
 syn keyword ngxDirectiveThirdParty contained passenger_sticky_sessions
+syn keyword ngxDirectiveThirdParty contained passenger_sticky_sessions_cookie_attributes
 syn keyword ngxDirectiveThirdParty contained passenger_sticky_sessions_cookie_name
+syn keyword ngxDirectiveThirdParty contained passenger_temp_path
 syn keyword ngxDirectiveThirdParty contained passenger_thread_count
 syn keyword ngxDirectiveThirdParty contained passenger_turbocaching
+syn keyword ngxDirectiveThirdParty contained passenger_use_global_queue
 syn keyword ngxDirectiveThirdParty contained passenger_user
 syn keyword ngxDirectiveThirdParty contained passenger_user_switching
 syn keyword ngxDirectiveThirdParty contained passenger_vary_turbocache_by_cookie
-syn keyword ngxDirectiveThirdPartyDeprecated contained passenger_analytics_log_group
-syn keyword ngxDirectiveThirdPartyDeprecated contained passenger_analytics_log_user
-syn keyword ngxDirectiveThirdPartyDeprecated contained passenger_debug_log_file
-syn keyword ngxDirectiveThirdPartyDeprecated contained passenger_use_global_queue
-syn keyword ngxDirectiveThirdPartyDeprecated contained rack_env
-syn keyword ngxDirectiveThirdPartyDeprecated contained rails_app_spawner_idle_time
-syn keyword ngxDirectiveThirdPartyDeprecated contained rails_env
-syn keyword ngxDirectiveThirdPartyDeprecated contained rails_framework_spawner_idle_time
-syn keyword ngxDirectiveThirdPartyDeprecated contained rails_spawn_method
-syn keyword ngxDirectiveThirdPartyDeprecated contained union_station_filter
-syn keyword ngxDirectiveThirdPartyDeprecated contained union_station_gateway_address
-syn keyword ngxDirectiveThirdPartyDeprecated contained union_station_gateway_cert
-syn keyword ngxDirectiveThirdPartyDeprecated contained union_station_gateway_port
-syn keyword ngxDirectiveThirdPartyDeprecated contained union_station_key
-syn keyword ngxDirectiveThirdPartyDeprecated contained union_station_proxy_address
-syn keyword ngxDirectiveThirdPartyDeprecated contained union_station_support
+syn keyword ngxDirectiveThirdParty contained rack_env
+syn keyword ngxDirectiveThirdParty contained rails_app_spawner_idle_time
+syn keyword ngxDirectiveThirdParty contained rails_env
+syn keyword ngxDirectiveThirdParty contained rails_framework_spawner_idle_time
+syn keyword ngxDirectiveThirdParty contained rails_spawn_method
+syn keyword ngxDirectiveThirdParty contained union_station_filter
+syn keyword ngxDirectiveThirdParty contained union_station_gateway_address
+syn keyword ngxDirectiveThirdParty contained union_station_gateway_cert
+syn keyword ngxDirectiveThirdParty contained union_station_gateway_port
+syn keyword ngxDirectiveThirdParty contained union_station_key
+syn keyword ngxDirectiveThirdParty contained union_station_proxy_address
+syn keyword ngxDirectiveThirdParty contained union_station_support
 
-" ngx_postgres is an upstream module that allows nginx to communicate directly with PostgreSQL database
-" https://github.com/FRiCKLE/ngx_postgres
+" https://github.com/konstruxi/ngx_postgres
 syn keyword ngxDirectiveThirdParty contained postgres_connect_timeout
 syn keyword ngxDirectiveThirdParty contained postgres_escape
 syn keyword ngxDirectiveThirdParty contained postgres_keepalive
@@ -1602,7 +1641,6 @@
 syn keyword ngxDirectiveThirdParty contained postgres_server
 syn keyword ngxDirectiveThirdParty contained postgres_set
 
-" ngx_rds_csv - Nginx output filter module to convert Resty-DBD-Streams (RDS) to Comma-Separated Values (CSV)
 " https://github.com/openresty/rds-csv-nginx-module
 syn keyword ngxDirectiveThirdParty contained rds_csv
 syn keyword ngxDirectiveThirdParty contained rds_csv_buffer_size
@@ -1611,7 +1649,6 @@
 syn keyword ngxDirectiveThirdParty contained rds_csv_field_separator
 syn keyword ngxDirectiveThirdParty contained rds_csv_row_terminator
 
-" ngx_rds_json - an output filter that formats Resty DBD Streams generated by ngx_drizzle and others to JSON
 " https://github.com/openresty/rds-json-nginx-module
 syn keyword ngxDirectiveThirdParty contained rds_json
 syn keyword ngxDirectiveThirdParty contained rds_json_buffer_size
@@ -1624,7 +1661,6 @@
 syn keyword ngxDirectiveThirdParty contained rds_json_success_property
 syn keyword ngxDirectiveThirdParty contained rds_json_user_property
 
-" ngx_redis2 - Nginx upstream module for the Redis 2.0 protocol
 " https://github.com/openresty/redis2-nginx-module
 syn keyword ngxDirectiveThirdParty contained redis2_bind
 syn keyword ngxDirectiveThirdParty contained redis2_buffer_size
@@ -1638,7 +1674,6 @@
 syn keyword ngxDirectiveThirdParty contained redis2_read_timeout
 syn keyword ngxDirectiveThirdParty contained redis2_send_timeout
 
-" NGINX-based Media Streaming Server
 " https://github.com/arut/nginx-rtmp-module
 syn keyword ngxDirectiveThirdParty contained ack_window
 syn keyword ngxDirectiveThirdParty contained application
@@ -1750,7 +1785,6 @@
 syn keyword ngxDirectiveThirdParty contained wait_key
 syn keyword ngxDirectiveThirdParty contained wait_video
 
-" ngx_set_misc - Various set_xxx directives added to nginx's rewrite module (md5/sha1, sql/json quoting, and many more)
 " https://github.com/openresty/set-misc-nginx-module
 syn keyword ngxDirectiveThirdParty contained set_base32_alphabet
 syn keyword ngxDirectiveThirdParty contained set_base32_padding
@@ -1770,6 +1804,7 @@
 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_md5
 syn keyword ngxDirectiveThirdParty contained set_misc_base32_padding
 syn keyword ngxDirectiveThirdParty contained set_quote_json_str
 syn keyword ngxDirectiveThirdParty contained set_quote_pgsql_str
@@ -1778,20 +1813,18 @@
 syn keyword ngxDirectiveThirdParty contained set_rotate
 syn keyword ngxDirectiveThirdParty contained set_secure_random_alphanum
 syn keyword ngxDirectiveThirdParty contained set_secure_random_lcalpha
+syn keyword ngxDirectiveThirdParty contained set_sha1
 syn keyword ngxDirectiveThirdParty contained set_unescape_uri
 
-" nginx-sflow-module
 " https://github.com/sflow/nginx-sflow-module
 syn keyword ngxDirectiveThirdParty contained sflow
 
-" Shibboleth auth request module for Nginx
 " https://github.com/nginx-shib/nginx-http-shibboleth
 syn keyword ngxDirectiveThirdParty contained shib_request
 syn keyword ngxDirectiveThirdParty contained shib_request_set
 syn keyword ngxDirectiveThirdParty contained shib_request_use_headers
 
-" nginx module which adds ability to cache static files
-" https://github.com/FRiCKLE/ngx_slowfs_cache
+" https://github.com/baysao/ngx_slowfs_cache
 syn keyword ngxDirectiveThirdParty contained slowfs_big_file_size
 syn keyword ngxDirectiveThirdParty contained slowfs_cache
 syn keyword ngxDirectiveThirdParty contained slowfs_cache_key
@@ -1801,8 +1834,7 @@
 syn keyword ngxDirectiveThirdParty contained slowfs_cache_valid
 syn keyword ngxDirectiveThirdParty contained slowfs_temp_path
 
-" Dynamic Image Transformation Module For nginx
-" https://github.com/cubicdaiya/ngx_small_light
+" https://github.com/kawakibi/ngx_small_light
 syn keyword ngxDirectiveThirdParty contained small_light
 syn keyword ngxDirectiveThirdParty contained small_light_buffer
 syn keyword ngxDirectiveThirdParty contained small_light_getparam_mode
@@ -1812,7 +1844,6 @@
 syn keyword ngxDirectiveThirdParty contained small_light_radius_max
 syn keyword ngxDirectiveThirdParty contained small_light_sigma_max
 
-" ngx_srcache - Transparent subrequest-based caching layout for arbitrary nginx locations
 " https://github.com/openresty/srcache-nginx-module
 syn keyword ngxDirectiveThirdParty contained srcache_buffer
 syn keyword ngxDirectiveThirdParty contained srcache_default_expire
@@ -1835,7 +1866,6 @@
 syn keyword ngxDirectiveThirdParty contained srcache_store_skip
 syn keyword ngxDirectiveThirdParty contained srcache_store_statuses
 
-" NGINX-based VOD Packager
 " https://github.com/kaltura/nginx-vod-module
 syn keyword ngxDirectiveThirdParty contained vod
 syn keyword ngxDirectiveThirdParty contained vod_align_segments_to_key_frames
@@ -1875,6 +1905,7 @@
 syn keyword ngxDirectiveThirdParty contained vod_manifest_duration_policy
 syn keyword ngxDirectiveThirdParty contained vod_manifest_segment_durations_mode
 syn keyword ngxDirectiveThirdParty contained vod_mapping_cache
+syn keyword ngxDirectiveThirdParty contained vod_max_frame_count
 syn keyword ngxDirectiveThirdParty contained vod_max_frames_size
 syn keyword ngxDirectiveThirdParty contained vod_max_mapping_response_size
 syn keyword ngxDirectiveThirdParty contained vod_max_metadata_size
@@ -1901,6 +1932,7 @@
 syn keyword ngxDirectiveThirdParty contained vod_secret_key
 syn keyword ngxDirectiveThirdParty contained vod_segment_count_policy
 syn keyword ngxDirectiveThirdParty contained vod_segment_duration
+syn keyword ngxDirectiveThirdParty contained vod_segment_max_frame_count
 syn keyword ngxDirectiveThirdParty contained vod_segments_base_url
 syn keyword ngxDirectiveThirdParty contained vod_source_clip_map_uri
 syn keyword ngxDirectiveThirdParty contained vod_speed_param_name
@@ -1910,7 +1942,6 @@
 syn keyword ngxDirectiveThirdParty contained vod_upstream_extra_args
 syn keyword ngxDirectiveThirdParty contained vod_upstream_location
 
-" Nginx virtual host traffic status module
 " https://github.com/vozlt/nginx-module-vts
 syn keyword ngxDirectiveThirdParty contained vhost_traffic_status
 syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_average_method
@@ -1934,7 +1965,6 @@
 syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_set_by_filter
 syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_zone
 
-" xss-nginx-module - Native cross-site scripting support in nginx
 " https://github.com/openresty/xss-nginx-module
 syn keyword ngxDirectiveThirdParty contained xss_callback_arg
 syn keyword ngxDirectiveThirdParty contained xss_check_status
@@ -1943,471 +1973,6 @@
 syn keyword ngxDirectiveThirdParty contained xss_output_type
 syn keyword ngxDirectiveThirdParty contained xss_override_status
 
-" Add support for array-typed variables to nginx config files
-" https://github.com/openresty/array-var-nginx-module
-syn keyword ngxDirectiveThirdParty contained array_join
-syn keyword ngxDirectiveThirdParty contained array_map
-syn keyword ngxDirectiveThirdParty contained array_map_op
-syn keyword ngxDirectiveThirdParty contained array_split
-
-" NGINX module for Brotli compression
-" https://github.com/eustas/ngx_brotli
-syn keyword ngxDirectiveThirdParty contained brotli
-syn keyword ngxDirectiveThirdParty contained brotli_buffers
-syn keyword ngxDirectiveThirdParty contained brotli_comp_level
-syn keyword ngxDirectiveThirdParty contained brotli_min_length
-syn keyword ngxDirectiveThirdParty contained brotli_static
-syn keyword ngxDirectiveThirdParty contained brotli_types
-syn keyword ngxDirectiveThirdParty contained brotli_window
-
-" form-input-nginx-module
-" https://github.com/calio/form-input-nginx-module
-syn keyword ngxDirectiveThirdParty contained set_form_input
-syn keyword ngxDirectiveThirdParty contained set_form_input_multi
-
-" character conversion nginx module using libiconv
-" https://github.com/calio/iconv-nginx-module
-syn keyword ngxDirectiveThirdParty contained iconv_buffer_size
-syn keyword ngxDirectiveThirdParty contained iconv_filter
-syn keyword ngxDirectiveThirdParty contained set_iconv
-
-" 3rd party modules list taken from
-" https://www.nginx.com/resources/wiki/modules/
-" ---------------------------------------------
-
-" Nginx Module for Authenticating Akamai G2O requests
-" https://github.com/kaltura/nginx_mod_akamai_g2o
-syn keyword ngxDirectiveThirdParty contained g2o
-syn keyword ngxDirectiveThirdParty contained g2o_data_header
-syn keyword ngxDirectiveThirdParty contained g2o_hash_function
-syn keyword ngxDirectiveThirdParty contained g2o_key
-syn keyword ngxDirectiveThirdParty contained g2o_log_level
-syn keyword ngxDirectiveThirdParty contained g2o_nonce
-syn keyword ngxDirectiveThirdParty contained g2o_sign_header
-syn keyword ngxDirectiveThirdParty contained g2o_time_window
-syn keyword ngxDirectiveThirdParty contained g2o_version
-
-" nginx_lua_module
-" https://github.com/alacner/nginx_lua_module
-syn keyword ngxDirectiveThirdParty contained lua_file
-
-" Nginx Audio Track for HTTP Live Streaming
-" https://github.com/flavioribeiro/nginx-audio-track-for-hls-module
-syn keyword ngxDirectiveThirdParty contained ngx_hls_audio_track
-syn keyword ngxDirectiveThirdParty contained ngx_hls_audio_track_output_format
-syn keyword ngxDirectiveThirdParty contained ngx_hls_audio_track_output_header
-syn keyword ngxDirectiveThirdParty contained ngx_hls_audio_track_rootpath
-
-" A Nginx module to dump backtrace when a worker process exits abnormally
-" https://github.com/alibaba/nginx-backtrace
-syn keyword ngxDirectiveThirdParty contained backtrace_log
-syn keyword ngxDirectiveThirdParty contained backtrace_max_stack_size
-
-" circle_gif module
-" https://github.com/evanmiller/nginx_circle_gif
-syn keyword ngxDirectiveThirdParty contained circle_gif
-syn keyword ngxDirectiveThirdParty contained circle_gif_max_radius
-syn keyword ngxDirectiveThirdParty contained circle_gif_min_radius
-syn keyword ngxDirectiveThirdParty contained circle_gif_step_radius
-
-" Upstream Consistent Hash
-" https://github.com/replay/ngx_http_consistent_hash
-syn keyword ngxDirectiveThirdParty contained consistent_hash
-
-" Nginx module for etags on dynamic content
-" https://github.com/kali/nginx-dynamic-etags
-syn keyword ngxDirectiveThirdParty contained dynamic_etags
-
-" Enhanced Nginx Memcached Module
-" https://github.com/bpaquet/ngx_http_enhanced_memcached_module
-syn keyword ngxDirectiveThirdParty contained enhanced_memcached_allow_delete
-syn keyword ngxDirectiveThirdParty contained enhanced_memcached_allow_put
-syn keyword ngxDirectiveThirdParty contained enhanced_memcached_bind
-syn keyword ngxDirectiveThirdParty contained enhanced_memcached_buffer_size
-syn keyword ngxDirectiveThirdParty contained enhanced_memcached_connect_timeout
-syn keyword ngxDirectiveThirdParty contained enhanced_memcached_flush
-syn keyword ngxDirectiveThirdParty contained enhanced_memcached_flush_namespace
-syn keyword ngxDirectiveThirdParty contained enhanced_memcached_hash_keys_with_md5
-syn keyword ngxDirectiveThirdParty contained enhanced_memcached_pass
-syn keyword ngxDirectiveThirdParty contained enhanced_memcached_read_timeout
-syn keyword ngxDirectiveThirdParty contained enhanced_memcached_send_timeout
-syn keyword ngxDirectiveThirdParty contained enhanced_memcached_stats
-
-" nginx max connections queue
-" https://github.com/ezmobius/nginx-ey-balancer
-syn keyword ngxDirectiveThirdParty contained max_connections_max_queue_length
-syn keyword ngxDirectiveThirdParty contained max_connections_queue_timeout
-
-" Nginx module for POST authentication and authorization
-" https://github.com/veruu/ngx_form_auth
-syn keyword ngxDirectiveThirdParty contained form_auth
-syn keyword ngxDirectiveThirdParty contained form_auth_login
-syn keyword ngxDirectiveThirdParty contained form_auth_pam_service
-syn keyword ngxDirectiveThirdParty contained form_auth_password
-syn keyword ngxDirectiveThirdParty contained form_auth_remote_user
-
-" ngx_http_accounting_module
-" https://github.com/Lax/ngx_http_accounting_module
-syn keyword ngxDirectiveThirdParty contained accounting
-syn keyword ngxDirectiveThirdParty contained accounting_id
-syn keyword ngxDirectiveThirdParty contained accounting_interval
-syn keyword ngxDirectiveThirdParty contained accounting_log
-syn keyword ngxDirectiveThirdParty contained accounting_perturb
-
-" concatenating files in a given context: CSS and JS files usually
-" https://github.com/alibaba/nginx-http-concat
-syn keyword ngxDirectiveThirdParty contained concat
-syn keyword ngxDirectiveThirdParty contained concat_delimiter
-syn keyword ngxDirectiveThirdParty contained concat_ignore_file_error
-syn keyword ngxDirectiveThirdParty contained concat_max_files
-syn keyword ngxDirectiveThirdParty contained concat_types
-syn keyword ngxDirectiveThirdParty contained concat_unique
-
-" update upstreams' config by restful interface
-" https://github.com/yzprofile/ngx_http_dyups_module
-syn keyword ngxDirectiveThirdParty contained dyups_interface
-syn keyword ngxDirectiveThirdParty contained dyups_shm_zone_size
-
-" add given content to the end of the response according to the condition specified
-" https://github.com/flygoast/ngx_http_footer_if_filter
-syn keyword ngxDirectiveThirdParty contained footer_if
-
-" NGINX HTTP Internal Redirect Module
-" https://github.com/flygoast/ngx_http_internal_redirect
-syn keyword ngxDirectiveThirdParty contained internal_redirect_if
-syn keyword ngxDirectiveThirdParty contained internal_redirect_if_no_postpone
-
-" nginx-ip-blocker
-" https://github.com/tmthrgd/nginx-ip-blocker
-syn keyword ngxDirectiveThirdParty contained ip_blocker
-
-" IP2Location Nginx
-" https://github.com/chrislim2888/ip2location-nginx
-syn keyword ngxDirectiveThirdParty contained ip2location_database
-
-" Limit upload rate
-" https://github.com/cfsego/limit_upload_rate
-syn keyword ngxDirectiveThirdParty contained limit_upload_rate
-syn keyword ngxDirectiveThirdParty contained limit_upload_rate_after
-syn keyword ngxDirectiveThirdParty contained limit_upload_rate_log_level
-
-" limit the number of connections to upstream
-" https://github.com/cfsego/nginx-limit-upstream
-syn keyword ngxDirectiveThirdParty contained limit_upstream_conn
-syn keyword ngxDirectiveThirdParty contained limit_upstream_log_level
-syn keyword ngxDirectiveThirdParty contained limit_upstream_zone
-
-" conditional accesslog for nginx
-" https://github.com/cfsego/ngx_log_if
-syn keyword ngxDirectiveThirdParty contained access_log_bypass_if
-
-" log messages over ZeroMQ
-" https://github.com/alticelabs/nginx-log-zmq
-syn keyword ngxDirectiveThirdParty contained log_zmq_endpoint
-syn keyword ngxDirectiveThirdParty contained log_zmq_format
-syn keyword ngxDirectiveThirdParty contained log_zmq_off
-syn keyword ngxDirectiveThirdParty contained log_zmq_server
-
-" simple module to uppercase/lowercase strings in the nginx config
-" https://github.com/replay/ngx_http_lower_upper_case
-syn keyword ngxDirectiveThirdParty contained lower
-syn keyword ngxDirectiveThirdParty contained upper
-
-" content filter for nginx, which returns the md5 hash of the content otherwise returned
-" https://github.com/kainswor/nginx_md5_filter
-syn keyword ngxDirectiveThirdParty contained md5_filter
-
-" Non-blocking upstream module for Nginx to connect to MongoDB
-" https://github.com/simpl/ngx_mongo
-syn keyword ngxDirectiveThirdParty contained mongo_auth
-syn keyword ngxDirectiveThirdParty contained mongo_bind
-syn keyword ngxDirectiveThirdParty contained mongo_buffer_size
-syn keyword ngxDirectiveThirdParty contained mongo_buffering
-syn keyword ngxDirectiveThirdParty contained mongo_buffers
-syn keyword ngxDirectiveThirdParty contained mongo_busy_buffers_size
-syn keyword ngxDirectiveThirdParty contained mongo_connect_timeout
-syn keyword ngxDirectiveThirdParty contained mongo_json
-syn keyword ngxDirectiveThirdParty contained mongo_next_upstream
-syn keyword ngxDirectiveThirdParty contained mongo_pass
-syn keyword ngxDirectiveThirdParty contained mongo_query
-syn keyword ngxDirectiveThirdParty contained mongo_read_timeout
-syn keyword ngxDirectiveThirdParty contained mongo_send_timeout
-
-" Nginx OCSP processing module designed for response caching
-" https://github.com/kyprizel/nginx_ocsp_proxy-module
-syn keyword ngxDirectiveThirdParty contained ocsp_cache_timeout
-syn keyword ngxDirectiveThirdParty contained ocsp_proxy
-
-" Nginx OpenSSL version check at startup
-" https://github.com/apcera/nginx-openssl-version
-syn keyword ngxDirectiveThirdParty contained openssl_builddate_minimum
-syn keyword ngxDirectiveThirdParty contained openssl_version_minimum
-
-" Automatic PageSpeed optimization module for Nginx
-" https://github.com/pagespeed/ngx_pagespeed
-syn keyword ngxDirectiveThirdParty contained pagespeed
-
-" PECL Memcache standard hashing compatible loadbalancer for Nginx
-" https://github.com/replay/ngx_http_php_memcache_standard_balancer
-syn keyword ngxDirectiveThirdParty contained hash_key
-
-" nginx module to parse php sessions
-" https://github.com/replay/ngx_http_php_session
-syn keyword ngxDirectiveThirdParty contained php_session_parse
-syn keyword ngxDirectiveThirdParty contained php_session_strip_formatting
-
-" Nginx HTTP rDNS module
-" https://github.com/flant/nginx-http-rdns
-syn keyword ngxDirectiveThirdParty contained rdns
-syn keyword ngxDirectiveThirdParty contained rdns_allow
-syn keyword ngxDirectiveThirdParty contained rdns_deny
-
-" Streaming regular expression replacement in response bodies
-" https://github.com/openresty/replace-filter-nginx-module
-syn keyword ngxDirectiveThirdParty contained replace_filter
-syn keyword ngxDirectiveThirdParty contained replace_filter_last_modified
-syn keyword ngxDirectiveThirdParty contained replace_filter_max_buffered_size
-syn keyword ngxDirectiveThirdParty contained replace_filter_skip
-syn keyword ngxDirectiveThirdParty contained replace_filter_types
-
-" Link RRDtool's graphing facilities directly into nginx
-" https://github.com/evanmiller/mod_rrd_graph
-syn keyword ngxDirectiveThirdParty contained rrd_graph
-syn keyword ngxDirectiveThirdParty contained rrd_graph_root
-
-" Module for nginx to proxy rtmp using http protocol
-" https://github.com/kwojtek/nginx-rtmpt-proxy-module
-syn keyword ngxDirectiveThirdParty contained rtmpt_proxy
-syn keyword ngxDirectiveThirdParty contained rtmpt_proxy_http_timeout
-syn keyword ngxDirectiveThirdParty contained rtmpt_proxy_rtmp_timeout
-syn keyword ngxDirectiveThirdParty contained rtmpt_proxy_stat
-syn keyword ngxDirectiveThirdParty contained rtmpt_proxy_stylesheet
-syn keyword ngxDirectiveThirdParty contained rtmpt_proxy_target
-
-" Syntactically Awesome NGINX Module
-" https://github.com/mneudert/sass-nginx-module
-syn keyword ngxDirectiveThirdParty contained sass_compile
-syn keyword ngxDirectiveThirdParty contained sass_error_log
-syn keyword ngxDirectiveThirdParty contained sass_include_path
-syn keyword ngxDirectiveThirdParty contained sass_indent
-syn keyword ngxDirectiveThirdParty contained sass_is_indented_syntax
-syn keyword ngxDirectiveThirdParty contained sass_linefeed
-syn keyword ngxDirectiveThirdParty contained sass_output_style
-syn keyword ngxDirectiveThirdParty contained sass_precision
-syn keyword ngxDirectiveThirdParty contained sass_source_comments
-syn keyword ngxDirectiveThirdParty contained sass_source_map_embed
-
-" Nginx Selective Cache Purge Module
-" https://github.com/wandenberg/nginx-selective-cache-purge-module
-syn keyword ngxDirectiveThirdParty contained selective_cache_purge_query
-syn keyword ngxDirectiveThirdParty contained selective_cache_purge_redis_database
-syn keyword ngxDirectiveThirdParty contained selective_cache_purge_redis_host
-syn keyword ngxDirectiveThirdParty contained selective_cache_purge_redis_password
-syn keyword ngxDirectiveThirdParty contained selective_cache_purge_redis_port
-syn keyword ngxDirectiveThirdParty contained selective_cache_purge_redis_unix_socket
-
-" cconv nginx module
-" https://github.com/liseen/set-cconv-nginx-module
-syn keyword ngxDirectiveThirdParty contained set_cconv_to_simp
-syn keyword ngxDirectiveThirdParty contained set_cconv_to_trad
-syn keyword ngxDirectiveThirdParty contained set_pinyin_to_normal
-
-" Nginx module that allows the setting of variables to the value of a variety of hashes
-" https://github.com/simpl/ngx_http_set_hash
-syn keyword ngxDirectiveThirdParty contained set_md5
-syn keyword ngxDirectiveThirdParty contained set_md5_upper
-syn keyword ngxDirectiveThirdParty contained set_murmur2
-syn keyword ngxDirectiveThirdParty contained set_murmur2_upper
-syn keyword ngxDirectiveThirdParty contained set_sha1
-syn keyword ngxDirectiveThirdParty contained set_sha1_upper
-
-" Nginx module to set the language of a request based on a number of options
-" https://github.com/simpl/ngx_http_set_lang
-syn keyword ngxDirectiveThirdParty contained lang_cookie
-syn keyword ngxDirectiveThirdParty contained lang_get_var
-syn keyword ngxDirectiveThirdParty contained lang_host
-syn keyword ngxDirectiveThirdParty contained lang_list
-syn keyword ngxDirectiveThirdParty contained lang_post_var
-syn keyword ngxDirectiveThirdParty contained lang_referer
-syn keyword ngxDirectiveThirdParty contained set_lang
-syn keyword ngxDirectiveThirdParty contained set_lang_method
-
-" Nginx Sorted Querystring Module
-" https://github.com/wandenberg/nginx-sorted-querystring-module
-syn keyword ngxDirectiveThirdParty contained sorted_querysting_filter_parameter
-
-" Nginx upstream module for Sphinx 2.x search daemon
-" https://github.com/reeteshranjan/sphinx2-nginx-module
-syn keyword ngxDirectiveThirdParty contained sphinx2_bind
-syn keyword ngxDirectiveThirdParty contained sphinx2_buffer_size
-syn keyword ngxDirectiveThirdParty contained sphinx2_connect_timeout
-syn keyword ngxDirectiveThirdParty contained sphinx2_next_upstream
-syn keyword ngxDirectiveThirdParty contained sphinx2_pass
-syn keyword ngxDirectiveThirdParty contained sphinx2_read_timeout
-syn keyword ngxDirectiveThirdParty contained sphinx2_send_timeout
-
-" Nginx module for retrieving user attributes and groups from SSSD
-" https://github.com/veruu/ngx_sssd_info
-syn keyword ngxDirectiveThirdParty contained sssd_info
-syn keyword ngxDirectiveThirdParty contained sssd_info_attribute
-syn keyword ngxDirectiveThirdParty contained sssd_info_attribute_separator
-syn keyword ngxDirectiveThirdParty contained sssd_info_attributes
-syn keyword ngxDirectiveThirdParty contained sssd_info_group
-syn keyword ngxDirectiveThirdParty contained sssd_info_group_separator
-syn keyword ngxDirectiveThirdParty contained sssd_info_groups
-syn keyword ngxDirectiveThirdParty contained sssd_info_output_to
-
-" An nginx module for sending statistics to statsd
-" https://github.com/zebrafishlabs/nginx-statsd
-syn keyword ngxDirectiveThirdParty contained statsd_count
-syn keyword ngxDirectiveThirdParty contained statsd_sample_rate
-syn keyword ngxDirectiveThirdParty contained statsd_server
-syn keyword ngxDirectiveThirdParty contained statsd_timing
-
-" ngx_stream_echo - TCP/stream echo module for NGINX (a port of the ngx_http_echo module)
-" https://github.com/openresty/stream-echo-nginx-module
-syn keyword ngxDirectiveThirdParty contained echo
-syn keyword ngxDirectiveThirdParty contained echo_client_error_log_level
-syn keyword ngxDirectiveThirdParty contained echo_discard_request
-syn keyword ngxDirectiveThirdParty contained echo_duplicate
-syn keyword ngxDirectiveThirdParty contained echo_flush_wait
-syn keyword ngxDirectiveThirdParty contained echo_lingering_close
-syn keyword ngxDirectiveThirdParty contained echo_lingering_time
-syn keyword ngxDirectiveThirdParty contained echo_lingering_timeout
-syn keyword ngxDirectiveThirdParty contained echo_read_buffer_size
-syn keyword ngxDirectiveThirdParty contained echo_read_bytes
-syn keyword ngxDirectiveThirdParty contained echo_read_line
-syn keyword ngxDirectiveThirdParty contained echo_read_timeout
-syn keyword ngxDirectiveThirdParty contained echo_request_data
-syn keyword ngxDirectiveThirdParty contained echo_send_timeout
-syn keyword ngxDirectiveThirdParty contained echo_sleep
-
-" Embed the power of Lua into NGINX TCP/UDP servers
-" https://github.com/openresty/stream-lua-nginx-module
-syn keyword ngxDirectiveThirdParty contained lua_add_variable
-syn keyword ngxDirectiveThirdParty contained preread_by_lua_block
-syn keyword ngxDirectiveThirdParty contained preread_by_lua_file
-syn keyword ngxDirectiveThirdParty contained preread_by_lua_no_postpone
-
-" nginx-upsync-module
-" https://github.com/weibocom/nginx-upsync-module
-syn keyword ngxDirectiveThirdParty contained upstream_show
-syn keyword ngxDirectiveThirdParty contained upsync
-syn keyword ngxDirectiveThirdParty contained upsync_dump_path
-syn keyword ngxDirectiveThirdParty contained upsync_lb
-
-" Whitespace stripper for nginx
-" https://github.com/evanmiller/mod_strip
-syn keyword ngxDirectiveThirdParty contained strip
-
-" Split one big HTTP/Range request to multiple subrange requesets
-" https://github.com/Qihoo360/ngx_http_subrange_module
-syn keyword ngxDirectiveThirdParty contained subrange
-
-" summarizer-nginx-module
-" https://github.com/reeteshranjan/summarizer-nginx-module
-syn keyword ngxDirectiveThirdParty contained summarizer_bind
-syn keyword ngxDirectiveThirdParty contained summarizer_buffer_size
-syn keyword ngxDirectiveThirdParty contained summarizer_connect_timeout
-syn keyword ngxDirectiveThirdParty contained summarizer_next_upstream
-syn keyword ngxDirectiveThirdParty contained summarizer_pass
-syn keyword ngxDirectiveThirdParty contained summarizer_read_timeout
-syn keyword ngxDirectiveThirdParty contained summarizer_send_timeout
-
-" nginx module providing API to communicate with supervisord and manage (start/stop) backends on-demand
-" https://github.com/FRiCKLE/ngx_supervisord
-syn keyword ngxDirectiveThirdParty contained supervisord
-syn keyword ngxDirectiveThirdParty contained supervisord_inherit_backend_status
-syn keyword ngxDirectiveThirdParty contained supervisord_name
-syn keyword ngxDirectiveThirdParty contained supervisord_start
-syn keyword ngxDirectiveThirdParty contained supervisord_stop
-
-" simple robot mitigation module using cookie based challenge/response technique. Not supported any more.
-" https://github.com/kyprizel/testcookie-nginx-module
-syn keyword ngxDirectiveThirdParty contained testcookie
-syn keyword ngxDirectiveThirdParty contained testcookie_arg
-syn keyword ngxDirectiveThirdParty contained testcookie_deny_keepalive
-syn keyword ngxDirectiveThirdParty contained testcookie_domain
-syn keyword ngxDirectiveThirdParty contained testcookie_expires
-syn keyword ngxDirectiveThirdParty contained testcookie_fallback
-syn keyword ngxDirectiveThirdParty contained testcookie_get_only
-syn keyword ngxDirectiveThirdParty contained testcookie_httponly_flag
-syn keyword ngxDirectiveThirdParty contained testcookie_https_location
-syn keyword ngxDirectiveThirdParty contained testcookie_internal
-syn keyword ngxDirectiveThirdParty contained testcookie_max_attempts
-syn keyword ngxDirectiveThirdParty contained testcookie_name
-syn keyword ngxDirectiveThirdParty contained testcookie_p3p
-syn keyword ngxDirectiveThirdParty contained testcookie_pass
-syn keyword ngxDirectiveThirdParty contained testcookie_path
-syn keyword ngxDirectiveThirdParty contained testcookie_port_in_redirect
-syn keyword ngxDirectiveThirdParty contained testcookie_redirect_via_refresh
-syn keyword ngxDirectiveThirdParty contained testcookie_refresh_encrypt_cookie
-syn keyword ngxDirectiveThirdParty contained testcookie_refresh_encrypt_cookie_iv
-syn keyword ngxDirectiveThirdParty contained testcookie_refresh_encrypt_cookie_key
-syn keyword ngxDirectiveThirdParty contained testcookie_refresh_status
-syn keyword ngxDirectiveThirdParty contained testcookie_refresh_template
-syn keyword ngxDirectiveThirdParty contained testcookie_samesite
-syn keyword ngxDirectiveThirdParty contained testcookie_secret
-syn keyword ngxDirectiveThirdParty contained testcookie_secure_flag
-syn keyword ngxDirectiveThirdParty contained testcookie_session
-syn keyword ngxDirectiveThirdParty contained testcookie_whitelist
-
-" ngx_http_types_filter_module
-" https://github.com/flygoast/ngx_http_types_filter
-syn keyword ngxDirectiveThirdParty contained types_filter
-syn keyword ngxDirectiveThirdParty contained types_filter_use_default
-
-" A module allowing the nginx to use files embedded in a zip file
-" https://github.com/youzee/nginx-unzip-module
-syn keyword ngxDirectiveThirdParty contained file_in_unzip
-syn keyword ngxDirectiveThirdParty contained file_in_unzip_archivefile
-syn keyword ngxDirectiveThirdParty contained file_in_unzip_extract
-
-" An asynchronous domain name resolve module for nginx upstream
-" https://github.com/wdaike/ngx_upstream_jdomain
-syn keyword ngxDirectiveThirdParty contained jdomain
-
-" Nginx url encoding converting module
-" https://github.com/vozlt/nginx-module-url
-syn keyword ngxDirectiveThirdParty contained url_encoding_convert
-syn keyword ngxDirectiveThirdParty contained url_encoding_convert_alloc_size
-syn keyword ngxDirectiveThirdParty contained url_encoding_convert_alloc_size_x
-syn keyword ngxDirectiveThirdParty contained url_encoding_convert_from
-syn keyword ngxDirectiveThirdParty contained url_encoding_convert_phase
-syn keyword ngxDirectiveThirdParty contained url_encoding_convert_to
-
-" A nginx module to match browsers and crawlers
-" https://github.com/alibaba/nginx-http-user-agent
-syn keyword ngxDirectiveThirdParty contained user_agent
-
-" nginx load-balancer module implementing ketama consistent hashing
-" https://github.com/flygoast/ngx_http_upstream_ketama_chash
-syn keyword ngxDirectiveThirdParty contained ketama_chash
-
-" nginx-sticky-module-ng
-" https://github.com/ayty-adrianomartins/nginx-sticky-module-ng
-syn keyword ngxDirectiveThirdParty contained sticky_no_fallback
-
-" dynamic linking and call the function of your application
-" https://github.com/Taymindis/nginx-link-function
-syn keyword ngxDirectiveThirdParty contained ngx_link_func_add_prop
-syn keyword ngxDirectiveThirdParty contained ngx_link_func_add_req_header
-syn keyword ngxDirectiveThirdParty contained ngx_link_func_ca_cert
-syn keyword ngxDirectiveThirdParty contained ngx_link_func_call
-syn keyword ngxDirectiveThirdParty contained ngx_link_func_download_link_lib
-syn keyword ngxDirectiveThirdParty contained ngx_link_func_lib
-syn keyword ngxDirectiveThirdParty contained ngx_link_func_shm_size
-syn keyword ngxDirectiveThirdParty contained ngx_link_func_subrequest
-
-" purge content from FastCGI, proxy, SCGI and uWSGI caches
-" https://github.com/torden/ngx_cache_purge
-syn keyword ngxDirectiveThirdParty contained cache_purge_response_type
-
-" set the flags "HttpOnly", "secure" and "SameSite" for cookies
-" https://github.com/AirisX/nginx_cookie_flag_module
-syn keyword ngxDirectiveThirdParty contained set_cookie_flag
-
-" Embed websockify into Nginx (convert any tcp connection into websocket)
 " https://github.com/tg123/websockify-nginx-module
 syn keyword ngxDirectiveThirdParty contained websockify_buffer_size
 syn keyword ngxDirectiveThirdParty contained websockify_connect_timeout
@@ -2415,55 +1980,6 @@
 syn keyword ngxDirectiveThirdParty contained websockify_read_timeout
 syn keyword ngxDirectiveThirdParty contained websockify_send_timeout
 
-" IP2Location Nginx
-" https://github.com/ip2location/ip2location-nginx
-syn keyword ngxDirectiveThirdParty contained ip2location_addresstype
-syn keyword ngxDirectiveThirdParty contained ip2location_areacode
-syn keyword ngxDirectiveThirdParty contained ip2location_category
-syn keyword ngxDirectiveThirdParty contained ip2location_city
-syn keyword ngxDirectiveThirdParty contained ip2location_country_long
-syn keyword ngxDirectiveThirdParty contained ip2location_country_short
-syn keyword ngxDirectiveThirdParty contained ip2location_domain
-syn keyword ngxDirectiveThirdParty contained ip2location_elevation
-syn keyword ngxDirectiveThirdParty contained ip2location_iddcode
-syn keyword ngxDirectiveThirdParty contained ip2location_isp
-syn keyword ngxDirectiveThirdParty contained ip2location_latitude
-syn keyword ngxDirectiveThirdParty contained ip2location_longitude
-syn keyword ngxDirectiveThirdParty contained ip2location_mcc
-syn keyword ngxDirectiveThirdParty contained ip2location_mnc
-syn keyword ngxDirectiveThirdParty contained ip2location_mobilebrand
-syn keyword ngxDirectiveThirdParty contained ip2location_netspeed
-syn keyword ngxDirectiveThirdParty contained ip2location_proxy
-syn keyword ngxDirectiveThirdParty contained ip2location_proxy_recursive
-syn keyword ngxDirectiveThirdParty contained ip2location_region
-syn keyword ngxDirectiveThirdParty contained ip2location_timezone
-syn keyword ngxDirectiveThirdParty contained ip2location_usagetype
-syn keyword ngxDirectiveThirdParty contained ip2location_weatherstationcode
-syn keyword ngxDirectiveThirdParty contained ip2location_weatherstationname
-syn keyword ngxDirectiveThirdParty contained ip2location_zipcode
-
-" IP2Proxy module for Nginx
-" https://github.com/ip2location/ip2proxy-nginx
-syn keyword ngxDirectiveThirdParty contained ip2proxy_as
-syn keyword ngxDirectiveThirdParty contained ip2proxy_asn
-syn keyword ngxDirectiveThirdParty contained ip2proxy_city
-syn keyword ngxDirectiveThirdParty contained ip2proxy_country_long
-syn keyword ngxDirectiveThirdParty contained ip2proxy_country_short
-syn keyword ngxDirectiveThirdParty contained ip2proxy_database
-syn keyword ngxDirectiveThirdParty contained ip2proxy_domain
-syn keyword ngxDirectiveThirdParty contained ip2proxy_isp
-syn keyword ngxDirectiveThirdParty contained ip2proxy_is_proxy
-syn keyword ngxDirectiveThirdParty contained ip2proxy_last_seen
-syn keyword ngxDirectiveThirdParty contained ip2proxy_provider
-syn keyword ngxDirectiveThirdParty contained ip2proxy_proxy
-syn keyword ngxDirectiveThirdParty contained ip2proxy_proxy_recursive
-syn keyword ngxDirectiveThirdParty contained ip2proxy_proxy_type
-syn keyword ngxDirectiveThirdParty contained ip2proxy_region
-syn keyword ngxDirectiveThirdParty contained ip2proxy_threat
-syn keyword ngxDirectiveThirdParty contained ip2proxy_usage_type
-
-
-
 " highlight
 
 hi def link ngxComment Comment
diff --git a/docs/text/LICENSE b/docs/text/LICENSE
index fd0c72d..fdedcb7 100644
--- a/docs/text/LICENSE
+++ b/docs/text/LICENSE
@@ -1,6 +1,6 @@
 /* 
  * Copyright (C) 2002-2021 Igor Sysoev
- * Copyright (C) 2011-2021 Nginx, Inc.
+ * Copyright (C) 2011-2022 Nginx, Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml
index 2f9c350..b084f6f 100644
--- a/docs/xml/nginx/changes.xml
+++ b/docs/xml/nginx/changes.xml
@@ -5,6 +5,107 @@
 <change_log title="nginx">
 
 
+<changes ver="1.23.0" date="2022-06-21">
+
+<change>
+<para lang="ru">
+Изменение во внутреннем API:
+теперь строки заголовков представлены связными списками.
+</para>
+<para lang="en">
+Change in internal API:
+now header lines are represented as linked lists.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+теперь nginx объединяет произвольные строки заголовков с одинаковыми именами
+при отправке на FastCGI-, SCGI- и uwsgi-бэкенды,
+в методе $r->header_in() модуля ngx_http_perl_module,
+и при доступе через переменные "$http_...", "$sent_http_...",
+"$sent_trailer_...", "$upstream_http_..." и "$upstream_trailer_...".
+</para>
+<para lang="en">
+now nginx combines arbitrary header lines with identical names
+when sending to FastCGI, SCGI, and uwsgi backends,
+in the $r->header_in() method of the ngx_http_perl_module,
+and during lookup of the "$http_...", "$sent_http_...",
+"$sent_trailer_...", "$upstream_http_...", and "$upstream_trailer_..."
+variables.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+если в заголовке ответа бэкенда было несколько строк "Vary",
+при кэшировании nginx учитывал только последнюю из них.
+</para>
+<para lang="en">
+if there were multiple "Vary" header lines in the backend response,
+nginx only used the last of them when caching.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+если в заголовке ответа бэкенда было несколько строк "WWW-Authenticate"
+и использовался перехват ошибок с кодом 401 от бэкенда
+или директива auth_request,
+nginx пересылал клиенту только первую из этих строк.
+</para>
+<para lang="en">
+if there were multiple "WWW-Authenticate" header lines in the backend response
+and errors with code 401 were intercepted
+or the "auth_request" directive was used,
+nginx only sent the first of the header lines to the client.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+уровень логгирования ошибок SSL "application data after close notify"
+понижен с уровня crit до info.
+</para>
+<para lang="en">
+the logging level of the "application data after close notify" SSL errors
+has been lowered from "crit" to "info".
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+соединения могли зависать, если nginx был собран на Linux 2.6.17 и новее,
+а использовался на системах без поддержки EPOLLRDHUP, в частности, на
+системах с эмуляцией epoll;
+ошибка появилась в 1.17.5.<br/>
+Спасибо Marcus Ball.
+</para>
+<para lang="en">
+connections might hang if nginx was built on Linux 2.6.17 or newer,
+but was used on systems without EPOLLRDHUP support, notably with epoll
+emulation layers;
+the bug had appeared in 1.17.5.<br/>
+Thanks to Marcus Ball.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+nginx не кэшировал ответ,
+если строка заголовка ответа "Expires" запрещала кэширование,
+а последующая строка заголовка "Cache-Control" разрешала кэширование.
+</para>
+<para lang="en">
+nginx did not cache the response
+if the "Expires" response header line disabled caching,
+but following "Cache-Control" header line enabled caching.
+</para>
+</change>
+
+</changes>
+
+
 <changes ver="1.21.6" date="2022-01-25">
 
 <change type="bugfix">
diff --git a/misc/GNUmakefile b/misc/GNUmakefile
index 58e9f7f..dfb5b9b 100644
--- a/misc/GNUmakefile
+++ b/misc/GNUmakefile
@@ -6,8 +6,8 @@
 
 CC =		cl
 OBJS =		objs.msvc8
-OPENSSL =	openssl-1.1.1m
-ZLIB =		zlib-1.2.11
+OPENSSL =	openssl-1.1.1p
+ZLIB =		zlib-1.2.12
 PCRE =		pcre2-10.39
 
 
@@ -15,12 +15,6 @@
 
 	mv $(TEMP)/$(NGINX)/auto/configure $(TEMP)/$(NGINX)
 
-	# delete incomplete sources
-	rm $(TEMP)/$(NGINX)/src/event/ngx_event_acceptex.c
-	rm $(TEMP)/$(NGINX)/src/event/ngx_event_connectex.c
-	rm $(TEMP)/$(NGINX)/src/event/modules/ngx_iocp_module.*
-	rm -r $(TEMP)/$(NGINX)/src/os/win32
-
 	mv $(TEMP)/$(NGINX)/docs/text/LICENSE $(TEMP)/$(NGINX)
 	mv $(TEMP)/$(NGINX)/docs/text/README $(TEMP)/$(NGINX)
 	mv $(TEMP)/$(NGINX)/docs/html $(TEMP)/$(NGINX)
diff --git a/src/core/nginx.h b/src/core/nginx.h
index cb13a4e..5a6fd08 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -13,8 +13,8 @@
 #define NGINX_NAME         "nginx"
 #endif
 
-#define nginx_version      1021006
-#define NGINX_VERSION      "1.21.6"
+#define nginx_version      1023000
+#define NGINX_VERSION      "1.23.0"
 #define NGINX_VER          NGINX_NAME "/" NGINX_VERSION
 
 #ifdef NGX_BUILD
diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h
index 8cc1475..6d3348d 100644
--- a/src/core/ngx_connection.h
+++ b/src/core/ngx_connection.h
@@ -184,6 +184,7 @@
     unsigned            tcp_nopush:2;    /* ngx_connection_tcp_nopush_e */
 
     unsigned            need_last_buf:1;
+    unsigned            need_flush_buf:1;
 
 #if (NGX_HAVE_SENDFILE_NODISKIO || NGX_COMPAT)
     unsigned            busy_count:2;
diff --git a/src/core/ngx_hash.h b/src/core/ngx_hash.h
index abc3cbe..3b57099 100644
--- a/src/core/ngx_hash.h
+++ b/src/core/ngx_hash.h
@@ -89,12 +89,15 @@
 } ngx_hash_keys_arrays_t;
 
 
-typedef struct {
+typedef struct ngx_table_elt_s  ngx_table_elt_t;
+
+struct ngx_table_elt_s {
     ngx_uint_t        hash;
     ngx_str_t         key;
     ngx_str_t         value;
     u_char           *lowcase_key;
-} ngx_table_elt_t;
+    ngx_table_elt_t  *next;
+};
 
 
 void *ngx_hash_find(ngx_hash_t *hash, ngx_uint_t key, u_char *name, size_t len);
diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c
index 6d129e5..b3947f5 100644
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -1389,6 +1389,7 @@
 
         rec->tcp->data = rec;
         rec->tcp->write->handler = ngx_resolver_tcp_write;
+        rec->tcp->write->cancelable = 1;
         rec->tcp->read->handler = ngx_resolver_tcp_read;
         rec->tcp->read->resolver = 1;
 
diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h
index 8cb2cdd..d3c3f83 100644
--- a/src/event/ngx_event.h
+++ b/src/event/ngx_event.h
@@ -499,12 +499,6 @@
 
 
 void ngx_event_accept(ngx_event_t *ev);
-#if !(NGX_WIN32)
-void ngx_event_recvmsg(ngx_event_t *ev);
-void ngx_udp_rbtree_insert_value(ngx_rbtree_node_t *temp,
-    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
-#endif
-void ngx_delete_udp_connection(void *data);
 ngx_int_t ngx_trylock_accept_mutex(ngx_cycle_t *cycle);
 ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle);
 u_char *ngx_accept_log_error(ngx_log_t *log, u_char *buf, size_t len);
@@ -534,6 +528,7 @@
 
 #include <ngx_event_timer.h>
 #include <ngx_event_posted.h>
+#include <ngx_event_udp.h>
 
 #if (NGX_WIN32)
 #include <ngx_iocp_module.h>
diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c
index adbbde6..668084a 100644
--- a/src/event/ngx_event_connect.c
+++ b/src/event/ngx_event_connect.c
@@ -179,6 +179,8 @@
         c->recv = ngx_udp_recv;
         c->send = ngx_send;
         c->send_chain = ngx_udp_send_chain;
+
+        c->need_flush_buf = 1;
     }
 
     c->log_error = pc->log_error;
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index fe23566..4abf790 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -3408,6 +3408,12 @@
 #endif
             || n == SSL_R_WRONG_VERSION_NUMBER                       /*  267 */
             || n == SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC        /*  281 */
+#ifdef SSL_R_APPLICATION_DATA_AFTER_CLOSE_NOTIFY
+            || n == SSL_R_APPLICATION_DATA_AFTER_CLOSE_NOTIFY        /*  291 */
+#endif
+#ifdef SSL_R_APPLICATION_DATA_ON_SHUTDOWN
+            || n == SSL_R_APPLICATION_DATA_ON_SHUTDOWN               /*  291 */
+#endif
 #ifdef SSL_R_RENEGOTIATE_EXT_TOO_LONG
             || n == SSL_R_RENEGOTIATE_EXT_TOO_LONG                   /*  335 */
             || n == SSL_R_RENEGOTIATION_ENCODING_ERR                 /*  336 */
diff --git a/src/event/ngx_event_udp.c b/src/event/ngx_event_udp.c
index a524ae0..1ac82c7 100644
--- a/src/event/ngx_event_udp.c
+++ b/src/event/ngx_event_udp.c
@@ -46,18 +46,8 @@
     ngx_connection_t  *c, *lc;
     static u_char      buffer[65535];
 
-#if (NGX_HAVE_MSGHDR_MSG_CONTROL)
-
-#if (NGX_HAVE_IP_RECVDSTADDR)
-    u_char             msg_control[CMSG_SPACE(sizeof(struct in_addr))];
-#elif (NGX_HAVE_IP_PKTINFO)
-    u_char             msg_control[CMSG_SPACE(sizeof(struct in_pktinfo))];
-#endif
-
-#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
-    u_char             msg_control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
-#endif
-
+#if (NGX_HAVE_ADDRINFO_CMSG)
+    u_char             msg_control[CMSG_SPACE(sizeof(ngx_addrinfo_t))];
 #endif
 
     if (ev->timedout) {
@@ -92,25 +82,13 @@
         msg.msg_iov = iov;
         msg.msg_iovlen = 1;
 
-#if (NGX_HAVE_MSGHDR_MSG_CONTROL)
-
+#if (NGX_HAVE_ADDRINFO_CMSG)
         if (ls->wildcard) {
+            msg.msg_control = &msg_control;
+            msg.msg_controllen = sizeof(msg_control);
 
-#if (NGX_HAVE_IP_RECVDSTADDR || NGX_HAVE_IP_PKTINFO)
-            if (ls->sockaddr->sa_family == AF_INET) {
-                msg.msg_control = &msg_control;
-                msg.msg_controllen = sizeof(msg_control);
-            }
-#endif
-
-#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
-            if (ls->sockaddr->sa_family == AF_INET6) {
-                msg.msg_control = &msg_control6;
-                msg.msg_controllen = sizeof(msg_control6);
-            }
-#endif
-        }
-
+            ngx_memzero(&msg_control, sizeof(msg_control));
+       }
 #endif
 
         n = recvmsg(lc->fd, &msg, 0);
@@ -129,7 +107,7 @@
             return;
         }
 
-#if (NGX_HAVE_MSGHDR_MSG_CONTROL)
+#if (NGX_HAVE_ADDRINFO_CMSG)
         if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) {
             ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
                           "recvmsg() truncated data");
@@ -159,7 +137,7 @@
         local_sockaddr = ls->sockaddr;
         local_socklen = ls->socklen;
 
-#if (NGX_HAVE_MSGHDR_MSG_CONTROL)
+#if (NGX_HAVE_ADDRINFO_CMSG)
 
         if (ls->wildcard) {
             struct cmsghdr  *cmsg;
@@ -171,59 +149,9 @@
                  cmsg != NULL;
                  cmsg = CMSG_NXTHDR(&msg, cmsg))
             {
-
-#if (NGX_HAVE_IP_RECVDSTADDR)
-
-                if (cmsg->cmsg_level == IPPROTO_IP
-                    && cmsg->cmsg_type == IP_RECVDSTADDR
-                    && local_sockaddr->sa_family == AF_INET)
-                {
-                    struct in_addr      *addr;
-                    struct sockaddr_in  *sin;
-
-                    addr = (struct in_addr *) CMSG_DATA(cmsg);
-                    sin = (struct sockaddr_in *) local_sockaddr;
-                    sin->sin_addr = *addr;
-
+                if (ngx_get_srcaddr_cmsg(cmsg, local_sockaddr) == NGX_OK) {
                     break;
                 }
-
-#elif (NGX_HAVE_IP_PKTINFO)
-
-                if (cmsg->cmsg_level == IPPROTO_IP
-                    && cmsg->cmsg_type == IP_PKTINFO
-                    && local_sockaddr->sa_family == AF_INET)
-                {
-                    struct in_pktinfo   *pkt;
-                    struct sockaddr_in  *sin;
-
-                    pkt = (struct in_pktinfo *) CMSG_DATA(cmsg);
-                    sin = (struct sockaddr_in *) local_sockaddr;
-                    sin->sin_addr = pkt->ipi_addr;
-
-                    break;
-                }
-
-#endif
-
-#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
-
-                if (cmsg->cmsg_level == IPPROTO_IPV6
-                    && cmsg->cmsg_type == IPV6_PKTINFO
-                    && local_sockaddr->sa_family == AF_INET6)
-                {
-                    struct in6_pktinfo   *pkt6;
-                    struct sockaddr_in6  *sin6;
-
-                    pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg);
-                    sin6 = (struct sockaddr_in6 *) local_sockaddr;
-                    sin6->sin6_addr = pkt6->ipi6_addr;
-
-                    break;
-                }
-
-#endif
-
             }
         }
 
@@ -318,6 +246,8 @@
         c->send = ngx_udp_send;
         c->send_chain = ngx_udp_send_chain;
 
+        c->need_flush_buf = 1;
+
         c->log = log;
         c->pool->log = log;
         c->listening = ls;
diff --git a/src/event/ngx_event_udp.h b/src/event/ngx_event_udp.h
new file mode 100644
index 0000000..51ca665
--- /dev/null
+++ b/src/event/ngx_event_udp.h
@@ -0,0 +1,58 @@
+
+/*
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_EVENT_UDP_H_INCLUDED_
+#define _NGX_EVENT_UDP_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#if !(NGX_WIN32)
+
+#if ((NGX_HAVE_MSGHDR_MSG_CONTROL)                                            \
+     && (NGX_HAVE_IP_SENDSRCADDR || NGX_HAVE_IP_RECVDSTADDR                   \
+         || NGX_HAVE_IP_PKTINFO                                               \
+         || (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)))
+#define NGX_HAVE_ADDRINFO_CMSG  1
+
+#endif
+
+
+#if (NGX_HAVE_ADDRINFO_CMSG)
+
+typedef union {
+#if (NGX_HAVE_IP_SENDSRCADDR || NGX_HAVE_IP_RECVDSTADDR)
+    struct in_addr        addr;
+#endif
+
+#if (NGX_HAVE_IP_PKTINFO)
+    struct in_pktinfo     pkt;
+#endif
+
+#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
+    struct in6_pktinfo    pkt6;
+#endif
+} ngx_addrinfo_t;
+
+size_t ngx_set_srcaddr_cmsg(struct cmsghdr *cmsg,
+    struct sockaddr *local_sockaddr);
+ngx_int_t ngx_get_srcaddr_cmsg(struct cmsghdr *cmsg,
+    struct sockaddr *local_sockaddr);
+
+#endif
+
+void ngx_event_recvmsg(ngx_event_t *ev);
+ssize_t ngx_sendmsg(ngx_connection_t *c, struct msghdr *msg, int flags);
+void ngx_udp_rbtree_insert_value(ngx_rbtree_node_t *temp,
+    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
+#endif
+
+void ngx_delete_udp_connection(void *data);
+
+
+#endif /* _NGX_EVENT_UDP_H_INCLUDED_ */
diff --git a/src/http/modules/ngx_http_auth_basic_module.c b/src/http/modules/ngx_http_auth_basic_module.c
index 0693319..02d41e8 100644
--- a/src/http/modules/ngx_http_auth_basic_module.c
+++ b/src/http/modules/ngx_http_auth_basic_module.c
@@ -339,6 +339,7 @@
     *p = '"';
 
     r->headers_out.www_authenticate->hash = 1;
+    r->headers_out.www_authenticate->next = NULL;
     ngx_str_set(&r->headers_out.www_authenticate->key, "WWW-Authenticate");
     r->headers_out.www_authenticate->value.data = basic;
     r->headers_out.www_authenticate->value.len = len;
diff --git a/src/http/modules/ngx_http_auth_request_module.c b/src/http/modules/ngx_http_auth_request_module.c
index bab79e4..8bc98aa 100644
--- a/src/http/modules/ngx_http_auth_request_module.c
+++ b/src/http/modules/ngx_http_auth_request_module.c
@@ -101,7 +101,7 @@
 static ngx_int_t
 ngx_http_auth_request_handler(ngx_http_request_t *r)
 {
-    ngx_table_elt_t               *h, *ho;
+    ngx_table_elt_t               *h, *ho, **ph;
     ngx_http_request_t            *sr;
     ngx_http_post_subrequest_t    *ps;
     ngx_http_auth_request_ctx_t   *ctx;
@@ -147,15 +147,21 @@
                 h = sr->upstream->headers_in.www_authenticate;
             }
 
-            if (h) {
+            ph = &r->headers_out.www_authenticate;
+
+            while (h) {
                 ho = ngx_list_push(&r->headers_out.headers);
                 if (ho == NULL) {
                     return NGX_ERROR;
                 }
 
                 *ho = *h;
+                ho->next = NULL;
 
-                r->headers_out.www_authenticate = ho;
+                *ph = ho;
+                ph = &ho->next;
+
+                h = h->next;
             }
 
             return ctx->status;
diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c
index 0cc9ae1..cfb9892 100644
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -1082,6 +1082,7 @@
     }
 
     r->headers_out.location->hash = 1;
+    r->headers_out.location->next = NULL;
     ngx_str_set(&r->headers_out.location->key, "Location");
 
     escape = 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len, NGX_ESCAPE_URI);
diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c
index 4a8dc33..2d9a18f 100644
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -835,14 +835,14 @@
 ngx_http_fastcgi_create_request(ngx_http_request_t *r)
 {
     off_t                         file_pos;
-    u_char                        ch, *pos, *lowcase_key;
+    u_char                        ch, sep, *pos, *lowcase_key;
     size_t                        size, len, key_len, val_len, padding,
                                   allocated;
     ngx_uint_t                    i, n, next, hash, skip_empty, header_params;
     ngx_buf_t                    *b;
     ngx_chain_t                  *cl, *body;
     ngx_list_part_t              *part;
-    ngx_table_elt_t              *header, **ignored;
+    ngx_table_elt_t              *header, *hn, **ignored;
     ngx_http_upstream_t          *u;
     ngx_http_script_code_pt       code;
     ngx_http_script_engine_t      e, le;
@@ -900,7 +900,11 @@
         allocated = 0;
         lowcase_key = NULL;
 
-        if (params->number) {
+        if (ngx_http_link_multi_headers(r) != NGX_OK) {
+            return NGX_ERROR;
+        }
+
+        if (params->number || r->headers_in.multi) {
             n = 0;
             part = &r->headers_in.headers.part;
 
@@ -930,6 +934,12 @@
                 i = 0;
             }
 
+            for (n = 0; n < header_params; n++) {
+                if (&header[i] == ignored[n]) {
+                    goto next_length;
+                }
+            }
+
             if (params->number) {
                 if (allocated < header[i].key.len) {
                     allocated = header[i].key.len + 16;
@@ -959,15 +969,23 @@
                     ignored[header_params++] = &header[i];
                     continue;
                 }
-
-                n += sizeof("HTTP_") - 1;
-
-            } else {
-                n = sizeof("HTTP_") - 1 + header[i].key.len;
             }
 
-            len += ((n > 127) ? 4 : 1) + ((header[i].value.len > 127) ? 4 : 1)
-                + n + header[i].value.len;
+            key_len = sizeof("HTTP_") - 1 + header[i].key.len;
+
+            val_len = header[i].value.len;
+
+            for (hn = header[i].next; hn; hn = hn->next) {
+                val_len += hn->value.len + 2;
+                ignored[header_params++] = hn;
+            }
+
+            len += ((key_len > 127) ? 4 : 1) + key_len
+                   + ((val_len > 127) ? 4 : 1) + val_len;
+
+        next_length:
+
+            continue;
         }
     }
 
@@ -1109,7 +1127,7 @@
 
             for (n = 0; n < header_params; n++) {
                 if (&header[i] == ignored[n]) {
-                    goto next;
+                    goto next_value;
                 }
             }
 
@@ -1125,6 +1143,11 @@
             }
 
             val_len = header[i].value.len;
+
+            for (hn = header[i].next; hn; hn = hn->next) {
+                val_len += hn->value.len + 2;
+            }
+
             if (val_len > 127) {
                 *b->last++ = (u_char) (((val_len >> 24) & 0x7f) | 0x80);
                 *b->last++ = (u_char) ((val_len >> 16) & 0xff);
@@ -1150,13 +1173,34 @@
                 *b->last++ = ch;
             }
 
-            b->last = ngx_copy(b->last, header[i].value.data, val_len);
+            b->last = ngx_copy(b->last, header[i].value.data,
+                               header[i].value.len);
+
+            if (header[i].next) {
+
+                if (header[i].key.len == sizeof("Cookie") - 1
+                    && ngx_strncasecmp(header[i].key.data, (u_char *) "Cookie",
+                                       sizeof("Cookie") - 1)
+                       == 0)
+                {
+                    sep = ';';
+
+                } else {
+                    sep = ',';
+                }
+
+                for (hn = header[i].next; hn; hn = hn->next) {
+                    *b->last++ = sep;
+                    *b->last++ = ' ';
+                    b->last = ngx_copy(b->last, hn->value.data, hn->value.len);
+                }
+            }
 
             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                            "fastcgi param: \"%*s: %*s\"",
                            key_len, b->last - (key_len + val_len),
                            val_len, b->last - val_len);
-        next:
+        next_value:
 
             continue;
         }
@@ -1963,8 +2007,12 @@
                 hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
                                    h->lowcase_key, h->key.len);
 
-                if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
-                    return NGX_ERROR;
+                if (hh) {
+                    rc = hh->handler(r, h, hh->offset);
+
+                    if (rc != NGX_OK) {
+                        return rc;
+                    }
                 }
 
                 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
diff --git a/src/http/modules/ngx_http_geo_module.c b/src/http/modules/ngx_http_geo_module.c
index 153b6aa..ef4e9b8 100644
--- a/src/http/modules/ngx_http_geo_module.c
+++ b/src/http/modules/ngx_http_geo_module.c
@@ -327,15 +327,15 @@
 ngx_http_geo_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx,
     ngx_addr_t *addr)
 {
-    ngx_array_t  *xfwd;
+    ngx_table_elt_t  *xfwd;
 
     if (ngx_http_geo_real_addr(r, ctx, addr) != NGX_OK) {
         return NGX_ERROR;
     }
 
-    xfwd = &r->headers_in.x_forwarded_for;
+    xfwd = r->headers_in.x_forwarded_for;
 
-    if (xfwd->nelts > 0 && ctx->proxies != NULL) {
+    if (xfwd != NULL && ctx->proxies != NULL) {
         (void) ngx_http_get_forwarded_addr(r, addr, xfwd, NULL,
                                            ctx->proxies, ctx->proxy_recursive);
     }
diff --git a/src/http/modules/ngx_http_geoip_module.c b/src/http/modules/ngx_http_geoip_module.c
index 5ea4f5f..eaf9876 100644
--- a/src/http/modules/ngx_http_geoip_module.c
+++ b/src/http/modules/ngx_http_geoip_module.c
@@ -240,16 +240,16 @@
 ngx_http_geoip_addr(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf)
 {
     ngx_addr_t           addr;
-    ngx_array_t         *xfwd;
+    ngx_table_elt_t     *xfwd;
     struct sockaddr_in  *sin;
 
     addr.sockaddr = r->connection->sockaddr;
     addr.socklen = r->connection->socklen;
     /* addr.name = r->connection->addr_text; */
 
-    xfwd = &r->headers_in.x_forwarded_for;
+    xfwd = r->headers_in.x_forwarded_for;
 
-    if (xfwd->nelts > 0 && gcf->proxies != NULL) {
+    if (xfwd != NULL && gcf->proxies != NULL) {
         (void) ngx_http_get_forwarded_addr(r, &addr, xfwd, NULL,
                                            gcf->proxies, gcf->proxy_recursive);
     }
@@ -292,7 +292,7 @@
 ngx_http_geoip_addr_v6(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf)
 {
     ngx_addr_t            addr;
-    ngx_array_t          *xfwd;
+    ngx_table_elt_t      *xfwd;
     in_addr_t             addr4;
     struct in6_addr       addr6;
     struct sockaddr_in   *sin;
@@ -302,9 +302,9 @@
     addr.socklen = r->connection->socklen;
     /* addr.name = r->connection->addr_text; */
 
-    xfwd = &r->headers_in.x_forwarded_for;
+    xfwd = r->headers_in.x_forwarded_for;
 
-    if (xfwd->nelts > 0 && gcf->proxies != NULL) {
+    if (xfwd != NULL && gcf->proxies != NULL) {
         (void) ngx_http_get_forwarded_addr(r, &addr, xfwd, NULL,
                                            gcf->proxies, gcf->proxy_recursive);
     }
diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c
index 864fc4f..617814e 100644
--- a/src/http/modules/ngx_http_grpc_module.c
+++ b/src/http/modules/ngx_http_grpc_module.c
@@ -1891,8 +1891,12 @@
                 hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
                                    h->lowcase_key, h->key.len);
 
-                if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
-                    return NGX_ERROR;
+                if (hh) {
+                    rc = hh->handler(r, h, hh->offset);
+
+                    if (rc != NGX_OK) {
+                        return rc;
+                    }
                 }
 
                 continue;
@@ -4902,8 +4906,9 @@
         return NGX_ERROR;
     }
 
-    if (glcf->upstream.ssl_certificate) {
-
+    if (glcf->upstream.ssl_certificate
+        && glcf->upstream.ssl_certificate->value.len)
+    {
         if (glcf->upstream.ssl_certificate_key == NULL) {
             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
                           "no \"grpc_ssl_certificate_key\" is defined "
diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c
index b8c5ccc..b775869 100644
--- a/src/http/modules/ngx_http_gzip_filter_module.c
+++ b/src/http/modules/ngx_http_gzip_filter_module.c
@@ -280,6 +280,7 @@
     }
 
     h->hash = 1;
+    h->next = NULL;
     ngx_str_set(&h->key, "Content-Encoding");
     ngx_str_set(&h->value, "gzip");
     r->headers_out.content_encoding = h;
diff --git a/src/http/modules/ngx_http_gzip_static_module.c b/src/http/modules/ngx_http_gzip_static_module.c
index 7652a9a..66fcc5d 100644
--- a/src/http/modules/ngx_http_gzip_static_module.c
+++ b/src/http/modules/ngx_http_gzip_static_module.c
@@ -242,6 +242,7 @@
     }
 
     h->hash = 1;
+    h->next = NULL;
     ngx_str_set(&h->key, "Content-Encoding");
     ngx_str_set(&h->value, "gzip");
     r->headers_out.content_encoding = h;
diff --git a/src/http/modules/ngx_http_headers_filter_module.c b/src/http/modules/ngx_http_headers_filter_module.c
index a4c8cc2..90e6da8 100644
--- a/src/http/modules/ngx_http_headers_filter_module.c
+++ b/src/http/modules/ngx_http_headers_filter_module.c
@@ -329,8 +329,7 @@
     time_t               now, expires_time, max_age;
     ngx_str_t            value;
     ngx_int_t            rc;
-    ngx_uint_t           i;
-    ngx_table_elt_t     *e, *cc, **ccp;
+    ngx_table_elt_t     *e, *cc;
     ngx_http_expires_t   expires;
 
     expires = conf->expires;
@@ -363,6 +362,7 @@
         }
 
         r->headers_out.expires = e;
+        e->next = NULL;
 
         e->hash = 1;
         ngx_str_set(&e->key, "Expires");
@@ -371,38 +371,29 @@
     len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT");
     e->value.len = len - 1;
 
-    ccp = r->headers_out.cache_control.elts;
+    cc = r->headers_out.cache_control;
 
-    if (ccp == NULL) {
-
-        if (ngx_array_init(&r->headers_out.cache_control, r->pool,
-                           1, sizeof(ngx_table_elt_t *))
-            != NGX_OK)
-        {
-            return NGX_ERROR;
-        }
+    if (cc == NULL) {
 
         cc = ngx_list_push(&r->headers_out.headers);
         if (cc == NULL) {
+            e->hash = 0;
             return NGX_ERROR;
         }
 
+        r->headers_out.cache_control = cc;
+        cc->next = NULL;
+
         cc->hash = 1;
         ngx_str_set(&cc->key, "Cache-Control");
 
-        ccp = ngx_array_push(&r->headers_out.cache_control);
-        if (ccp == NULL) {
-            return NGX_ERROR;
-        }
-
-        *ccp = cc;
-
     } else {
-        for (i = 1; i < r->headers_out.cache_control.nelts; i++) {
-            ccp[i]->hash = 0;
+        for (cc = cc->next; cc; cc = cc->next) {
+            cc->hash = 0;
         }
 
-        cc = ccp[0];
+        cc = r->headers_out.cache_control;
+        cc->next = NULL;
     }
 
     if (expires == NGX_HTTP_EXPIRES_EPOCH) {
@@ -420,6 +411,8 @@
 
     e->value.data = ngx_pnalloc(r->pool, len);
     if (e->value.data == NULL) {
+        e->hash = 0;
+        cc->hash = 0;
         return NGX_ERROR;
     }
 
@@ -457,6 +450,7 @@
     cc->value.data = ngx_pnalloc(r->pool,
                                  sizeof("max-age=") + NGX_TIME_T_LEN + 1);
     if (cc->value.data == NULL) {
+        cc->hash = 0;
         return NGX_ERROR;
     }
 
@@ -564,22 +558,12 @@
 ngx_http_add_multi_header_lines(ngx_http_request_t *r,
     ngx_http_header_val_t *hv, ngx_str_t *value)
 {
-    ngx_array_t      *pa;
     ngx_table_elt_t  *h, **ph;
 
     if (value->len == 0) {
         return NGX_OK;
     }
 
-    pa = (ngx_array_t *) ((char *) &r->headers_out + hv->offset);
-
-    if (pa->elts == NULL) {
-        if (ngx_array_init(pa, r->pool, 1, sizeof(ngx_table_elt_t *)) != NGX_OK)
-        {
-            return NGX_ERROR;
-        }
-    }
-
     h = ngx_list_push(&r->headers_out.headers);
     if (h == NULL) {
         return NGX_ERROR;
@@ -589,12 +573,12 @@
     h->key = hv->key;
     h->value = *value;
 
-    ph = ngx_array_push(pa);
-    if (ph == NULL) {
-        return NGX_ERROR;
-    }
+    ph = (ngx_table_elt_t **) ((char *) &r->headers_out + hv->offset);
+
+    while (*ph) { ph = &(*ph)->next; }
 
     *ph = h;
+    h->next = NULL;
 
     return NGX_OK;
 }
@@ -642,6 +626,7 @@
         }
 
         *old = h;
+        h->next = NULL;
     }
 
     h->hash = 1;
diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c
index c82df6e..11bbd91 100644
--- a/src/http/modules/ngx_http_memcached_module.c
+++ b/src/http/modules/ngx_http_memcached_module.c
@@ -401,6 +401,7 @@
             }
 
             h->hash = 1;
+            h->next = NULL;
             ngx_str_set(&h->key, "Content-Encoding");
             ngx_str_set(&h->value, "gzip");
             r->headers_out.content_encoding = h;
diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c
index 9c3f627..5721efb 100644
--- a/src/http/modules/ngx_http_mp4_module.c
+++ b/src/http/modules/ngx_http_mp4_module.c
@@ -2331,7 +2331,7 @@
         }
 
         start_sample += count;
-        start_time -= count * duration;
+        start_time -= (uint64_t) count * duration;
         entries--;
         entry++;
     }
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index cf91525..52d0e69 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -1937,8 +1937,12 @@
             hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
                                h->lowcase_key, h->key.len);
 
-            if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
-                return NGX_ERROR;
+            if (hh) {
+                rc = hh->handler(r, h, hh->offset);
+
+                if (rc != NGX_OK) {
+                    return rc;
+                }
             }
 
             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -1972,6 +1976,7 @@
                 ngx_str_set(&h->key, "Server");
                 ngx_str_null(&h->value);
                 h->lowcase_key = (u_char *) "server";
+                h->next = NULL;
             }
 
             if (r->upstream->headers_in.date == NULL) {
@@ -1985,6 +1990,7 @@
                 ngx_str_set(&h->key, "Date");
                 ngx_str_null(&h->value);
                 h->lowcase_key = (u_char *) "date";
+                h->next = NULL;
             }
 
             /* clear content length if response is chunked */
@@ -2566,22 +2572,20 @@
 ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data)
 {
-    size_t             len;
-    u_char            *p;
-    ngx_uint_t         i, n;
-    ngx_table_elt_t  **h;
+    size_t            len;
+    u_char           *p;
+    ngx_table_elt_t  *h, *xfwd;
 
     v->valid = 1;
     v->no_cacheable = 0;
     v->not_found = 0;
 
-    n = r->headers_in.x_forwarded_for.nelts;
-    h = r->headers_in.x_forwarded_for.elts;
+    xfwd = r->headers_in.x_forwarded_for;
 
     len = 0;
 
-    for (i = 0; i < n; i++) {
-        len += h[i]->value.len + sizeof(", ") - 1;
+    for (h = xfwd; h; h = h->next) {
+        len += h->value.len + sizeof(", ") - 1;
     }
 
     if (len == 0) {
@@ -2600,8 +2604,8 @@
     v->len = len;
     v->data = p;
 
-    for (i = 0; i < n; i++) {
-        p = ngx_copy(p, h[i]->value.data, h[i]->value.len);
+    for (h = xfwd; h; h = h->next) {
+        p = ngx_copy(p, h->value.data, h->value.len);
         *p++ = ','; *p++ = ' ';
     }
 
@@ -4982,8 +4986,9 @@
         return NGX_ERROR;
     }
 
-    if (plcf->upstream.ssl_certificate) {
-
+    if (plcf->upstream.ssl_certificate
+        && plcf->upstream.ssl_certificate->value.len)
+    {
         if (plcf->upstream.ssl_certificate_key == NULL) {
             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
                           "no \"proxy_ssl_certificate_key\" is defined "
diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c
index ae08ebb..fa408b7 100644
--- a/src/http/modules/ngx_http_range_filter_module.c
+++ b/src/http/modules/ngx_http_range_filter_module.c
@@ -258,6 +258,7 @@
     }
 
     r->headers_out.accept_ranges->hash = 1;
+    r->headers_out.accept_ranges->next = NULL;
     ngx_str_set(&r->headers_out.accept_ranges->key, "Accept-Ranges");
     ngx_str_set(&r->headers_out.accept_ranges->value, "bytes");
 
@@ -427,6 +428,7 @@
     r->headers_out.content_range = content_range;
 
     content_range->hash = 1;
+    content_range->next = NULL;
     ngx_str_set(&content_range->key, "Content-Range");
 
     content_range->value.data = ngx_pnalloc(r->pool,
@@ -599,6 +601,7 @@
     r->headers_out.content_range = content_range;
 
     content_range->hash = 1;
+    content_range->next = NULL;
     ngx_str_set(&content_range->key, "Content-Range");
 
     content_range->value.data = ngx_pnalloc(r->pool,
diff --git a/src/http/modules/ngx_http_realip_module.c b/src/http/modules/ngx_http_realip_module.c
index 9586ebe..f6731e7 100644
--- a/src/http/modules/ngx_http_realip_module.c
+++ b/src/http/modules/ngx_http_realip_module.c
@@ -134,9 +134,8 @@
     ngx_str_t                   *value;
     ngx_uint_t                   i, hash;
     ngx_addr_t                   addr;
-    ngx_array_t                 *xfwd;
     ngx_list_part_t             *part;
-    ngx_table_elt_t             *header;
+    ngx_table_elt_t             *header, *xfwd;
     ngx_connection_t            *c;
     ngx_http_realip_ctx_t       *ctx;
     ngx_http_realip_loc_conf_t  *rlcf;
@@ -168,9 +167,9 @@
 
     case NGX_HTTP_REALIP_XFWD:
 
-        xfwd = &r->headers_in.x_forwarded_for;
+        xfwd = r->headers_in.x_forwarded_for;
 
-        if (xfwd->elts == NULL) {
+        if (xfwd == NULL) {
             return NGX_DECLINED;
         }
 
diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c
index e5d31ae..9fc18dc 100644
--- a/src/http/modules/ngx_http_scgi_module.c
+++ b/src/http/modules/ngx_http_scgi_module.c
@@ -633,14 +633,14 @@
 ngx_http_scgi_create_request(ngx_http_request_t *r)
 {
     off_t                         content_length_n;
-    u_char                        ch, *key, *val, *lowcase_key;
+    u_char                        ch, sep, *key, *val, *lowcase_key;
     size_t                        len, key_len, val_len, allocated;
     ngx_buf_t                    *b;
     ngx_str_t                     content_length;
     ngx_uint_t                    i, n, hash, skip_empty, header_params;
     ngx_chain_t                  *cl, *body;
     ngx_list_part_t              *part;
-    ngx_table_elt_t              *header, **ignored;
+    ngx_table_elt_t              *header, *hn, **ignored;
     ngx_http_scgi_params_t       *params;
     ngx_http_script_code_pt       code;
     ngx_http_script_engine_t      e, le;
@@ -707,7 +707,11 @@
         allocated = 0;
         lowcase_key = NULL;
 
-        if (params->number) {
+        if (ngx_http_link_multi_headers(r) != NGX_OK) {
+            return NGX_ERROR;
+        }
+
+        if (params->number || r->headers_in.multi) {
             n = 0;
             part = &r->headers_in.headers.part;
 
@@ -737,6 +741,12 @@
                 i = 0;
             }
 
+            for (n = 0; n < header_params; n++) {
+                if (&header[i] == ignored[n]) {
+                    goto next_length;
+                }
+            }
+
             if (params->number) {
                 if (allocated < header[i].key.len) {
                     allocated = header[i].key.len + 16;
@@ -770,6 +780,15 @@
 
             len += sizeof("HTTP_") - 1 + header[i].key.len + 1
                 + header[i].value.len + 1;
+
+            for (hn = header[i].next; hn; hn = hn->next) {
+                len += hn->value.len + 2;
+                ignored[header_params++] = hn;
+            }
+
+        next_length:
+
+            continue;
         }
     }
 
@@ -869,7 +888,7 @@
 
             for (n = 0; n < header_params; n++) {
                 if (&header[i] == ignored[n]) {
-                    goto next;
+                    goto next_value;
                 }
             }
 
@@ -893,12 +912,33 @@
 
             val = b->last;
             b->last = ngx_copy(val, header[i].value.data, header[i].value.len);
+
+            if (header[i].next) {
+
+                if (header[i].key.len == sizeof("Cookie") - 1
+                    && ngx_strncasecmp(header[i].key.data, (u_char *) "Cookie",
+                                       sizeof("Cookie") - 1)
+                       == 0)
+                {
+                    sep = ';';
+
+                } else {
+                    sep = ',';
+                }
+
+                for (hn = header[i].next; hn; hn = hn->next) {
+                    *b->last++ = sep;
+                    *b->last++ = ' ';
+                    b->last = ngx_copy(b->last, hn->value.data, hn->value.len);
+                }
+            }
+
             *b->last++ = (u_char) 0;
 
             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                            "scgi param: \"%s: %s\"", key, val);
 
-        next:
+        next_value:
 
             continue;
         }
@@ -1074,8 +1114,12 @@
             hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
                                h->lowcase_key, h->key.len);
 
-            if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
-                return NGX_ERROR;
+            if (hh) {
+                rc = hh->handler(r, h, hh->offset);
+
+                if (rc != NGX_OK) {
+                    return rc;
+                }
             }
 
             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c
index cf29d5a..e30565d 100644
--- a/src/http/modules/ngx_http_static_module.c
+++ b/src/http/modules/ngx_http_static_module.c
@@ -195,6 +195,7 @@
         }
 
         r->headers_out.location->hash = 1;
+        r->headers_out.location->next = NULL;
         ngx_str_set(&r->headers_out.location->key, "Location");
         r->headers_out.location->value.len = len;
         r->headers_out.location->value.data = location;
diff --git a/src/http/modules/ngx_http_userid_filter_module.c b/src/http/modules/ngx_http_userid_filter_module.c
index 1e33c5c..e528444 100644
--- a/src/http/modules/ngx_http_userid_filter_module.c
+++ b/src/http/modules/ngx_http_userid_filter_module.c
@@ -319,10 +319,9 @@
 static ngx_http_userid_ctx_t *
 ngx_http_userid_get_uid(ngx_http_request_t *r, ngx_http_userid_conf_t *conf)
 {
-    ngx_int_t                n;
-    ngx_str_t                src, dst;
-    ngx_table_elt_t        **cookies;
-    ngx_http_userid_ctx_t   *ctx;
+    ngx_str_t               src, dst;
+    ngx_table_elt_t        *cookie;
+    ngx_http_userid_ctx_t  *ctx;
 
     ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module);
 
@@ -339,9 +338,9 @@
         ngx_http_set_ctx(r, ctx, ngx_http_userid_filter_module);
     }
 
-    n = ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &conf->name,
-                                          &ctx->cookie);
-    if (n == NGX_DECLINED) {
+    cookie = ngx_http_parse_multi_header_lines(r, r->headers_in.cookie,
+                                               &conf->name, &ctx->cookie);
+    if (cookie == NULL) {
         return ctx;
     }
 
@@ -349,10 +348,9 @@
                    "uid cookie: \"%V\"", &ctx->cookie);
 
     if (ctx->cookie.len < 22) {
-        cookies = r->headers_in.cookies.elts;
         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                       "client sent too short userid cookie \"%V\"",
-                      &cookies[n]->value);
+                      &cookie->value);
         return ctx;
     }
 
@@ -370,10 +368,9 @@
     dst.data = (u_char *) ctx->uid_got;
 
     if (ngx_decode_base64(&dst, &src) == NGX_ERROR) {
-        cookies = r->headers_in.cookies.elts;
         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                       "client sent invalid userid cookie \"%V\"",
-                      &cookies[n]->value);
+                      &cookie->value);
         return ctx;
     }
 
diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c
index d46741a..1dcee1e 100644
--- a/src/http/modules/ngx_http_uwsgi_module.c
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -845,13 +845,13 @@
 static ngx_int_t
 ngx_http_uwsgi_create_request(ngx_http_request_t *r)
 {
-    u_char                        ch, *lowcase_key;
+    u_char                        ch, sep, *lowcase_key;
     size_t                        key_len, val_len, len, allocated;
     ngx_uint_t                    i, n, hash, skip_empty, header_params;
     ngx_buf_t                    *b;
     ngx_chain_t                  *cl, *body;
     ngx_list_part_t              *part;
-    ngx_table_elt_t              *header, **ignored;
+    ngx_table_elt_t              *header, *hn, **ignored;
     ngx_http_uwsgi_params_t      *params;
     ngx_http_script_code_pt       code;
     ngx_http_script_engine_t      e, le;
@@ -905,7 +905,11 @@
         allocated = 0;
         lowcase_key = NULL;
 
-        if (params->number) {
+        if (ngx_http_link_multi_headers(r) != NGX_OK) {
+            return NGX_ERROR;
+        }
+
+        if (params->number || r->headers_in.multi) {
             n = 0;
             part = &r->headers_in.headers.part;
 
@@ -935,6 +939,12 @@
                 i = 0;
             }
 
+            for (n = 0; n < header_params; n++) {
+                if (&header[i] == ignored[n]) {
+                    goto next_length;
+                }
+            }
+
             if (params->number) {
                 if (allocated < header[i].key.len) {
                     allocated = header[i].key.len + 16;
@@ -968,6 +978,15 @@
 
             len += 2 + sizeof("HTTP_") - 1 + header[i].key.len
                  + 2 + header[i].value.len;
+
+            for (hn = header[i].next; hn; hn = hn->next) {
+                len += hn->value.len + 2;
+                ignored[header_params++] = hn;
+            }
+
+        next_length:
+
+            continue;
         }
     }
 
@@ -1086,7 +1105,7 @@
 
             for (n = 0; n < header_params; n++) {
                 if (&header[i] == ignored[n]) {
-                    goto next;
+                    goto next_value;
                 }
             }
 
@@ -1109,15 +1128,41 @@
             }
 
             val_len = header[i].value.len;
+
+            for (hn = header[i].next; hn; hn = hn->next) {
+                val_len += hn->value.len + 2;
+            }
+
             *b->last++ = (u_char) (val_len & 0xff);
             *b->last++ = (u_char) ((val_len >> 8) & 0xff);
-            b->last = ngx_copy(b->last, header[i].value.data, val_len);
+            b->last = ngx_copy(b->last, header[i].value.data,
+                               header[i].value.len);
+
+            if (header[i].next) {
+
+                if (header[i].key.len == sizeof("Cookie") - 1
+                    && ngx_strncasecmp(header[i].key.data, (u_char *) "Cookie",
+                                       sizeof("Cookie") - 1)
+                       == 0)
+                {
+                    sep = ';';
+
+                } else {
+                    sep = ',';
+                }
+
+                for (hn = header[i].next; hn; hn = hn->next) {
+                    *b->last++ = sep;
+                    *b->last++ = ' ';
+                    b->last = ngx_copy(b->last, hn->value.data, hn->value.len);
+                }
+            }
 
             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                            "uwsgi param: \"%*s: %*s\"",
                            key_len, b->last - (key_len + 2 + val_len),
                            val_len, b->last - val_len);
-        next:
+        next_value:
 
             continue;
         }
@@ -1295,8 +1340,12 @@
             hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
                                h->lowcase_key, h->key.len);
 
-            if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
-                return NGX_ERROR;
+            if (hh) {
+                rc = hh->handler(r, h, hh->offset);
+
+                if (rc != NGX_OK) {
+                    return rc;
+                }
             }
 
             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -2438,8 +2487,9 @@
         return NGX_ERROR;
     }
 
-    if (uwcf->upstream.ssl_certificate) {
-
+    if (uwcf->upstream.ssl_certificate
+        && uwcf->upstream.ssl_certificate->value.len)
+    {
         if (uwcf->upstream.ssl_certificate_key == NULL) {
             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
                           "no \"uwsgi_ssl_certificate_key\" is defined "
diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs
index 260f5b7..fd59e29 100644
--- a/src/http/modules/perl/nginx.xs
+++ b/src/http/modules/perl/nginx.xs
@@ -269,10 +269,9 @@
     u_char                     *p, *lowcase_key, *value, sep;
     STRLEN                      len;
     ssize_t                     size;
-    ngx_uint_t                  i, n, hash;
-    ngx_array_t                *a;
+    ngx_uint_t                  i, hash;
     ngx_list_part_t            *part;
-    ngx_table_elt_t            *h, **ph;
+    ngx_table_elt_t            *h, *header, **ph;
     ngx_http_header_t          *hh;
     ngx_http_core_main_conf_t  *cmcf;
 
@@ -302,78 +301,23 @@
 
     if (hh) {
 
-        if (hh->offset == offsetof(ngx_http_headers_in_t, cookies)) {
+        if (hh->offset == offsetof(ngx_http_headers_in_t, cookie)) {
             sep = ';';
-            goto multi;
-        }
-#if (NGX_HTTP_X_FORWARDED_FOR || NGX_COMPAT)
-        if (hh->offset == offsetof(ngx_http_headers_in_t, x_forwarded_for)) {
+
+        } else {
             sep = ',';
-            goto multi;
         }
-#endif
 
         ph = (ngx_table_elt_t **) ((char *) &r->headers_in + hh->offset);
 
-        if (*ph) {
-            ngx_http_perl_set_targ((*ph)->value.data, (*ph)->value.len);
-
-            goto done;
-        }
-
-        XSRETURN_UNDEF;
-
-    multi:
-
-        /* Cookie, X-Forwarded-For */
-
-        a = (ngx_array_t *) ((char *) &r->headers_in + hh->offset);
-
-        n = a->nelts;
-
-        if (n == 0) {
-            XSRETURN_UNDEF;
-        }
-
-        ph = a->elts;
-
-        if (n == 1) {
-            ngx_http_perl_set_targ((*ph)->value.data, (*ph)->value.len);
-
-            goto done;
-        }
-
-        size = - (ssize_t) (sizeof("; ") - 1);
-
-        for (i = 0; i < n; i++) {
-            size += ph[i]->value.len + sizeof("; ") - 1;
-        }
-
-        value = ngx_pnalloc(r->pool, size);
-        if (value == NULL) {
-            ctx->error = 1;
-            croak("ngx_pnalloc() failed");
-        }
-
-        p = value;
-
-        for (i = 0; /* void */ ; i++) {
-            p = ngx_copy(p, ph[i]->value.data, ph[i]->value.len);
-
-            if (i == n - 1) {
-                break;
-            }
-
-            *p++ = sep; *p++ = ' ';
-        }
-
-        ngx_http_perl_set_targ(value, size);
-
-        goto done;
+        goto found;
     }
 
     /* iterate over all headers */
 
+    sep = ',';
+    ph = &header;
+
     part = &r->headers_in.headers.part;
     h = part->elts;
 
@@ -395,12 +339,49 @@
             continue;
         }
 
-        ngx_http_perl_set_targ(h[i].value.data, h[i].value.len);
+        *ph = &h[i];
+        ph = &h[i].next;
+    }
 
+    *ph = NULL;
+    ph = &header;
+
+    found:
+
+    if (*ph == NULL) {
+        XSRETURN_UNDEF;
+    }
+
+    if ((*ph)->next == NULL) {
+        ngx_http_perl_set_targ((*ph)->value.data, (*ph)->value.len);
         goto done;
     }
 
-    XSRETURN_UNDEF;
+    size = - (ssize_t) (sizeof("; ") - 1);
+
+    for (h = *ph; h; h = h->next) {
+        size += h->value.len + sizeof("; ") - 1;
+    }
+
+    value = ngx_pnalloc(r->pool, size);
+    if (value == NULL) {
+        ctx->error = 1;
+        croak("ngx_pnalloc() failed");
+    }
+
+    p = value;
+
+    for (h = *ph; h; h = h->next) {
+        p = ngx_copy(p, h->value.data, h->value.len);
+
+        if (h->next == NULL) {
+            break;
+        }
+
+        *p++ = sep; *p++ = ' ';
+    }
+
+    ngx_http_perl_set_targ(value, size);
 
     done:
 
@@ -591,6 +572,7 @@
     }
 
     header->hash = 1;
+    header->next = NULL;
 
     if (ngx_http_perl_sv2str(aTHX_ r, &header->key, key) != NGX_OK) {
         header->hash = 0;
diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h
index 4781938..0545ee6 100644
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -111,10 +111,10 @@
     ngx_str_t *args, ngx_uint_t *flags);
 ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b,
     ngx_uint_t allow_underscores);
-ngx_int_t ngx_http_parse_multi_header_lines(ngx_array_t *headers,
-    ngx_str_t *name, ngx_str_t *value);
-ngx_int_t ngx_http_parse_set_cookie_lines(ngx_array_t *headers,
-    ngx_str_t *name, ngx_str_t *value);
+ngx_table_elt_t *ngx_http_parse_multi_header_lines(ngx_http_request_t *r,
+    ngx_table_elt_t *headers, ngx_str_t *name, ngx_str_t *value);
+ngx_table_elt_t *ngx_http_parse_set_cookie_lines(ngx_http_request_t *r,
+    ngx_table_elt_t *headers, ngx_str_t *name, ngx_str_t *value);
 ngx_int_t ngx_http_arg(ngx_http_request_t *r, u_char *name, size_t len,
     ngx_str_t *value);
 void ngx_http_split_args(ngx_http_request_t *r, ngx_str_t *uri,
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index 6e4c042..7acf215 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -1007,6 +1007,7 @@
         }
 
         r->headers_out.location->hash = 1;
+        r->headers_out.location->next = NULL;
         ngx_str_set(&r->headers_out.location->key, "Location");
 
         if (r->args.len == 0) {
@@ -1087,6 +1088,7 @@
 ngx_http_core_access_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph)
 {
     ngx_int_t                  rc;
+    ngx_table_elt_t           *h;
     ngx_http_core_loc_conf_t  *clcf;
 
     if (r != r->main) {
@@ -1121,8 +1123,8 @@
         if (rc == NGX_OK) {
             r->access_code = 0;
 
-            if (r->headers_out.www_authenticate) {
-                r->headers_out.www_authenticate->hash = 0;
+            for (h = r->headers_out.www_authenticate; h; h = h->next) {
+                h->hash = 0;
             }
 
             r->phase_handler = ph->next;
@@ -1687,6 +1689,7 @@
     }
 
     etag->hash = 1;
+    etag->next = NULL;
     ngx_str_set(&etag->key, "ETag");
 
     etag->value.data = ngx_pnalloc(r->pool, NGX_OFF_T_LEN + NGX_TIME_T_LEN + 3);
@@ -1781,6 +1784,7 @@
         }
 
         r->headers_out.location->hash = 1;
+        r->headers_out.location->next = NULL;
         ngx_str_set(&r->headers_out.location->key, "Location");
         r->headers_out.location->value = val;
 
@@ -2024,8 +2028,7 @@
 {
     time_t                     date, expires;
     ngx_uint_t                 p;
-    ngx_array_t               *cc;
-    ngx_table_elt_t           *e, *d, *ae;
+    ngx_table_elt_t           *e, *d, *ae, *cc;
     ngx_http_core_loc_conf_t  *clcf;
 
     r->gzip_tested = 1;
@@ -2118,30 +2121,30 @@
         return NGX_DECLINED;
     }
 
-    cc = &r->headers_out.cache_control;
+    cc = r->headers_out.cache_control;
 
-    if (cc->elts) {
+    if (cc) {
 
         if ((p & NGX_HTTP_GZIP_PROXIED_NO_CACHE)
-            && ngx_http_parse_multi_header_lines(cc, &ngx_http_gzip_no_cache,
+            && ngx_http_parse_multi_header_lines(r, cc, &ngx_http_gzip_no_cache,
                                                  NULL)
-               >= 0)
+               != NULL)
         {
             goto ok;
         }
 
         if ((p & NGX_HTTP_GZIP_PROXIED_NO_STORE)
-            && ngx_http_parse_multi_header_lines(cc, &ngx_http_gzip_no_store,
+            && ngx_http_parse_multi_header_lines(r, cc, &ngx_http_gzip_no_store,
                                                  NULL)
-               >= 0)
+               != NULL)
         {
             goto ok;
         }
 
         if ((p & NGX_HTTP_GZIP_PROXIED_PRIVATE)
-            && ngx_http_parse_multi_header_lines(cc, &ngx_http_gzip_private,
+            && ngx_http_parse_multi_header_lines(r, cc, &ngx_http_gzip_private,
                                                  NULL)
-               >= 0)
+               != NULL)
         {
             goto ok;
         }
@@ -2712,12 +2715,12 @@
 
 ngx_int_t
 ngx_http_get_forwarded_addr(ngx_http_request_t *r, ngx_addr_t *addr,
-    ngx_array_t *headers, ngx_str_t *value, ngx_array_t *proxies,
+    ngx_table_elt_t *headers, ngx_str_t *value, ngx_array_t *proxies,
     int recursive)
 {
-    ngx_int_t          rc;
-    ngx_uint_t         i, found;
-    ngx_table_elt_t  **h;
+    ngx_int_t         rc;
+    ngx_uint_t        found;
+    ngx_table_elt_t  *h, *next;
 
     if (headers == NULL) {
         return ngx_http_get_forwarded_addr_internal(r, addr, value->data,
@@ -2725,16 +2728,23 @@
                                                     recursive);
     }
 
-    i = headers->nelts;
-    h = headers->elts;
+    /* revert headers order */
+
+    for (h = headers, headers = NULL; h; h = next) {
+        next = h->next;
+        h->next = headers;
+        headers = h;
+    }
+
+    /* iterate over all headers in reverse order */
 
     rc = NGX_DECLINED;
 
     found = 0;
 
-    while (i-- > 0) {
-        rc = ngx_http_get_forwarded_addr_internal(r, addr, h[i]->value.data,
-                                                  h[i]->value.len, proxies,
+    for (h = headers; h; h = h->next) {
+        rc = ngx_http_get_forwarded_addr_internal(r, addr, h->value.data,
+                                                  h->value.len, proxies,
                                                   recursive);
 
         if (!recursive) {
@@ -2753,6 +2763,14 @@
         found = 1;
     }
 
+    /* restore headers order */
+
+    for (h = headers, headers = NULL; h; h = next) {
+        next = h->next;
+        h->next = headers;
+        headers = h;
+    }
+
     return rc;
 }
 
@@ -2802,6 +2820,80 @@
 }
 
 
+ngx_int_t
+ngx_http_link_multi_headers(ngx_http_request_t *r)
+{
+    ngx_uint_t        i, j;
+    ngx_list_part_t  *part, *ppart;
+    ngx_table_elt_t  *header, *pheader, **ph;
+
+    if (r->headers_in.multi_linked) {
+        return NGX_OK;
+    }
+
+    r->headers_in.multi_linked = 1;
+
+    part = &r->headers_in.headers.part;
+    header = part->elts;
+
+    for (i = 0; /* void */; i++) {
+
+        if (i >= part->nelts) {
+            if (part->next == NULL) {
+                break;
+            }
+
+            part = part->next;
+            header = part->elts;
+            i = 0;
+        }
+
+        header[i].next = NULL;
+
+        /*
+         * search for previous headers with the same name;
+         * if there are any, link to them
+         */
+
+        ppart = &r->headers_in.headers.part;
+        pheader = ppart->elts;
+
+        for (j = 0; /* void */; j++) {
+
+            if (j >= ppart->nelts) {
+                if (ppart->next == NULL) {
+                    break;
+                }
+
+                ppart = ppart->next;
+                pheader = ppart->elts;
+                j = 0;
+            }
+
+            if (part == ppart && i == j) {
+                break;
+            }
+
+            if (header[i].key.len == pheader[j].key.len
+                && ngx_strncasecmp(header[i].key.data, pheader[j].key.data,
+                                   header[i].key.len)
+                   == 0)
+            {
+                ph = &pheader[j].next;
+                while (*ph) { ph = &(*ph)->next; }
+                *ph = &header[i];
+
+                r->headers_in.multi = 1;
+
+                break;
+            }
+        }
+    }
+
+    return NGX_OK;
+}
+
+
 static char *
 ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
 {
diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h
index 74098c2..102054b 100644
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -529,9 +529,11 @@
     ngx_http_core_loc_conf_t *clcf, ngx_str_t *path, ngx_open_file_info_t *of);
 
 ngx_int_t ngx_http_get_forwarded_addr(ngx_http_request_t *r, ngx_addr_t *addr,
-    ngx_array_t *headers, ngx_str_t *value, ngx_array_t *proxies,
+    ngx_table_elt_t *headers, ngx_str_t *value, ngx_array_t *proxies,
     int recursive);
 
+ngx_int_t ngx_http_link_multi_headers(ngx_http_request_t *r);
+
 
 extern ngx_module_t  ngx_http_core_module;
 
diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c
index c40093b..4d2f6c4 100644
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -1756,6 +1756,11 @@
             break;
         }
 
+        if (fcn->deleting) {
+            wait = 1;
+            break;
+        }
+
         p = ngx_hex_dump(key, (u_char *) &fcn->node.key,
                          sizeof(ngx_rbtree_key_t));
         len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t);
diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c
index 6460da2..d4f2dae 100644
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -1960,27 +1960,24 @@
 }
 
 
-ngx_int_t
-ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_str_t *name,
-    ngx_str_t *value)
+ngx_table_elt_t *
+ngx_http_parse_multi_header_lines(ngx_http_request_t *r,
+    ngx_table_elt_t *headers, ngx_str_t *name, ngx_str_t *value)
 {
-    ngx_uint_t         i;
-    u_char            *start, *last, *end, ch;
-    ngx_table_elt_t  **h;
+    u_char           *start, *last, *end, ch;
+    ngx_table_elt_t  *h;
 
-    h = headers->elts;
+    for (h = headers; h; h = h->next) {
 
-    for (i = 0; i < headers->nelts; i++) {
+        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "parse header: \"%V: %V\"", &h->key, &h->value);
 
-        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, headers->pool->log, 0,
-                       "parse header: \"%V: %V\"", &h[i]->key, &h[i]->value);
-
-        if (name->len > h[i]->value.len) {
+        if (name->len > h->value.len) {
             continue;
         }
 
-        start = h[i]->value.data;
-        end = h[i]->value.data + h[i]->value.len;
+        start = h->value.data;
+        end = h->value.data + h->value.len;
 
         while (start < end) {
 
@@ -1994,7 +1991,7 @@
 
             if (value == NULL) {
                 if (start == end || *start == ',') {
-                    return i;
+                    return h;
                 }
 
                 goto skip;
@@ -2014,7 +2011,7 @@
             value->len = last - start;
             value->data = start;
 
-            return i;
+            return h;
 
         skip:
 
@@ -2029,31 +2026,28 @@
         }
     }
 
-    return NGX_DECLINED;
+    return NULL;
 }
 
 
-ngx_int_t
-ngx_http_parse_set_cookie_lines(ngx_array_t *headers, ngx_str_t *name,
-    ngx_str_t *value)
+ngx_table_elt_t *
+ngx_http_parse_set_cookie_lines(ngx_http_request_t *r,
+    ngx_table_elt_t *headers, ngx_str_t *name, ngx_str_t *value)
 {
-    ngx_uint_t         i;
-    u_char            *start, *last, *end;
-    ngx_table_elt_t  **h;
+    u_char           *start, *last, *end;
+    ngx_table_elt_t  *h;
 
-    h = headers->elts;
+    for (h = headers; h; h = h->next) {
 
-    for (i = 0; i < headers->nelts; i++) {
+        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "parse header: \"%V: %V\"", &h->key, &h->value);
 
-        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, headers->pool->log, 0,
-                       "parse header: \"%V: %V\"", &h[i]->key, &h[i]->value);
-
-        if (name->len >= h[i]->value.len) {
+        if (name->len >= h->value.len) {
             continue;
         }
 
-        start = h[i]->value.data;
-        end = h[i]->value.data + h[i]->value.len;
+        start = h->value.data;
+        end = h->value.data + h->value.len;
 
         if (ngx_strncasecmp(start, name->data, name->len) != 0) {
             continue;
@@ -2077,10 +2071,10 @@
         value->len = last - start;
         value->data = start;
 
-        return i;
+        return h;
     }
 
-    return NGX_DECLINED;
+    return NULL;
 }
 
 
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index 4c5bfbf..b2cd82e 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -22,8 +22,6 @@
     ngx_table_elt_t *h, ngx_uint_t offset);
 static ngx_int_t ngx_http_process_unique_header_line(ngx_http_request_t *r,
     ngx_table_elt_t *h, ngx_uint_t offset);
-static ngx_int_t ngx_http_process_multi_header_lines(ngx_http_request_t *r,
-    ngx_table_elt_t *h, ngx_uint_t offset);
 static ngx_int_t ngx_http_process_host(ngx_http_request_t *r,
     ngx_table_elt_t *h, ngx_uint_t offset);
 static ngx_int_t ngx_http_process_connection(ngx_http_request_t *r,
@@ -164,7 +162,7 @@
 #if (NGX_HTTP_X_FORWARDED_FOR || NGX_COMPAT)
     { ngx_string("X-Forwarded-For"),
                  offsetof(ngx_http_headers_in_t, x_forwarded_for),
-                 ngx_http_process_multi_header_lines },
+                 ngx_http_process_header_line },
 #endif
 
 #if (NGX_HTTP_REALIP || NGX_COMPAT)
@@ -196,8 +194,8 @@
                  ngx_http_process_header_line },
 #endif
 
-    { ngx_string("Cookie"), offsetof(ngx_http_headers_in_t, cookies),
-                 ngx_http_process_multi_header_lines },
+    { ngx_string("Cookie"), offsetof(ngx_http_headers_in_t, cookie),
+                 ngx_http_process_header_line },
 
     { ngx_null_string, 0, NULL }
 };
@@ -1906,9 +1904,10 @@
 
     ph = (ngx_table_elt_t **) ((char *) &r->headers_in + offset);
 
-    if (*ph == NULL) {
-        *ph = h;
-    }
+    while (*ph) { ph = &(*ph)->next; }
+
+    *ph = h;
+    h->next = NULL;
 
     return NGX_OK;
 }
@@ -1924,6 +1923,7 @@
 
     if (*ph == NULL) {
         *ph = h;
+        h->next = NULL;
         return NGX_OK;
     }
 
@@ -1956,6 +1956,7 @@
     }
 
     r->headers_in.host = h;
+    h->next = NULL;
 
     host = h->value;
 
@@ -1991,8 +1992,8 @@
 ngx_http_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h,
     ngx_uint_t offset)
 {
-    if (r->headers_in.connection == NULL) {
-        r->headers_in.connection = h;
+    if (ngx_http_process_header_line(r, h, offset) != NGX_OK) {
+        return NGX_ERROR;
     }
 
 #if (NGX_HTTP_V2)
@@ -2024,12 +2025,10 @@
 {
     u_char  *user_agent, *msie;
 
-    if (r->headers_in.user_agent) {
-        return NGX_OK;
+    if (ngx_http_process_header_line(r, h, offset) != NGX_OK) {
+        return NGX_ERROR;
     }
 
-    r->headers_in.user_agent = h;
-
     /* check some widespread browsers while the header is in CPU cache */
 
     user_agent = h->value.data;
@@ -2091,35 +2090,6 @@
 }
 
 
-static ngx_int_t
-ngx_http_process_multi_header_lines(ngx_http_request_t *r, ngx_table_elt_t *h,
-    ngx_uint_t offset)
-{
-    ngx_array_t       *headers;
-    ngx_table_elt_t  **ph;
-
-    headers = (ngx_array_t *) ((char *) &r->headers_in + offset);
-
-    if (headers->elts == NULL) {
-        if (ngx_array_init(headers, r->pool, 1, sizeof(ngx_table_elt_t *))
-            != NGX_OK)
-        {
-            ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
-            return NGX_ERROR;
-        }
-    }
-
-    ph = ngx_array_push(headers);
-    if (ph == NULL) {
-        ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
-        return NGX_ERROR;
-    }
-
-    *ph = h;
-    return NGX_OK;
-}
-
-
 ngx_int_t
 ngx_http_process_request_header(ngx_http_request_t *r)
 {
diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
index 3ea3490..f4bf85a 100644
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -212,7 +212,7 @@
     ngx_table_elt_t                  *keep_alive;
 
 #if (NGX_HTTP_X_FORWARDED_FOR || NGX_COMPAT)
-    ngx_array_t                       x_forwarded_for;
+    ngx_table_elt_t                  *x_forwarded_for;
 #endif
 
 #if (NGX_HTTP_REALIP || NGX_COMPAT)
@@ -231,17 +231,19 @@
     ngx_table_elt_t                  *date;
 #endif
 
+    ngx_table_elt_t                  *cookie;
+
     ngx_str_t                         user;
     ngx_str_t                         passwd;
 
-    ngx_array_t                       cookies;
-
     ngx_str_t                         server;
     off_t                             content_length_n;
     time_t                            keep_alive_n;
 
     unsigned                          connection_type:2;
     unsigned                          chunked:1;
+    unsigned                          multi:1;
+    unsigned                          multi_linked:1;
     unsigned                          msie:1;
     unsigned                          msie6:1;
     unsigned                          opera:1;
@@ -272,6 +274,9 @@
     ngx_table_elt_t                  *expires;
     ngx_table_elt_t                  *etag;
 
+    ngx_table_elt_t                  *cache_control;
+    ngx_table_elt_t                  *link;
+
     ngx_str_t                        *override_charset;
 
     size_t                            content_type_len;
@@ -280,9 +285,6 @@
     u_char                           *content_type_lowcase;
     ngx_uint_t                        content_type_hash;
 
-    ngx_array_t                       cache_control;
-    ngx_array_t                       link;
-
     off_t                             content_length_n;
     off_t                             content_offset;
     time_t                            date_time;
diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c
index bebdbd9..a2b9f1b 100644
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -1243,6 +1243,7 @@
         }
 
         r->headers_out.location->hash = 1;
+        r->headers_out.location->next = NULL;
         ngx_str_set(&r->headers_out.location->key, "Location");
         r->headers_out.location->value = e->buf;
 
diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c
index 9630697..a29cecc 100644
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -649,6 +649,7 @@
     }
 
     location->hash = 1;
+    location->next = NULL;
     ngx_str_set(&location->key, "Location");
     location->value = uri;
 
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index ef88d72..9c7ada6 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -101,6 +101,9 @@
 
 static ngx_int_t ngx_http_upstream_process_header_line(ngx_http_request_t *r,
     ngx_table_elt_t *h, ngx_uint_t offset);
+static ngx_int_t
+    ngx_http_upstream_process_multi_header_lines(ngx_http_request_t *r,
+    ngx_table_elt_t *h, ngx_uint_t offset);
 static ngx_int_t ngx_http_upstream_process_content_length(ngx_http_request_t *r,
     ngx_table_elt_t *h, ngx_uint_t offset);
 static ngx_int_t ngx_http_upstream_process_last_modified(ngx_http_request_t *r,
@@ -147,11 +150,6 @@
 static ngx_int_t ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r,
     ngx_table_elt_t *h, ngx_uint_t offset);
 
-#if (NGX_HTTP_GZIP || NGX_COMPAT)
-static ngx_int_t ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r,
-    ngx_table_elt_t *h, ngx_uint_t offset);
-#endif
-
 static ngx_int_t ngx_http_upstream_add_variables(ngx_conf_t *cf);
 static ngx_int_t ngx_http_upstream_addr_variable(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
@@ -231,7 +229,7 @@
                  offsetof(ngx_http_headers_out_t, server), 0 },
 
     { ngx_string("WWW-Authenticate"),
-                 ngx_http_upstream_process_header_line,
+                 ngx_http_upstream_process_multi_header_lines,
                  offsetof(ngx_http_upstream_headers_in_t, www_authenticate),
                  ngx_http_upstream_copy_header_line, 0, 0 },
 
@@ -241,12 +239,13 @@
                  ngx_http_upstream_rewrite_location, 0, 0 },
 
     { ngx_string("Refresh"),
-                 ngx_http_upstream_ignore_header_line, 0,
+                 ngx_http_upstream_process_header_line,
+                 offsetof(ngx_http_upstream_headers_in_t, refresh),
                  ngx_http_upstream_rewrite_refresh, 0, 0 },
 
     { ngx_string("Set-Cookie"),
                  ngx_http_upstream_process_set_cookie,
-                 offsetof(ngx_http_upstream_headers_in_t, cookies),
+                 offsetof(ngx_http_upstream_headers_in_t, set_cookie),
                  ngx_http_upstream_rewrite_set_cookie, 0, 1 },
 
     { ngx_string("Content-Disposition"),
@@ -264,8 +263,7 @@
                  offsetof(ngx_http_headers_out_t, expires), 1 },
 
     { ngx_string("Accept-Ranges"),
-                 ngx_http_upstream_process_header_line,
-                 offsetof(ngx_http_upstream_headers_in_t, accept_ranges),
+                 ngx_http_upstream_ignore_header_line, 0,
                  ngx_http_upstream_copy_allow_ranges,
                  offsetof(ngx_http_headers_out_t, accept_ranges), 1 },
 
@@ -316,12 +314,10 @@
                  ngx_http_upstream_process_transfer_encoding, 0,
                  ngx_http_upstream_ignore_header_line, 0, 0 },
 
-#if (NGX_HTTP_GZIP || NGX_COMPAT)
     { ngx_string("Content-Encoding"),
-                 ngx_http_upstream_process_header_line,
-                 offsetof(ngx_http_upstream_headers_in_t, content_encoding),
-                 ngx_http_upstream_copy_content_encoding, 0, 0 },
-#endif
+                 ngx_http_upstream_ignore_header_line, 0,
+                 ngx_http_upstream_copy_header_line,
+                 offsetof(ngx_http_headers_out_t, content_encoding), 0 },
 
     { ngx_null_string, NULL, 0, NULL, 0, 0 }
 };
@@ -1694,8 +1690,10 @@
         }
     }
 
-    if (u->conf->ssl_certificate && (u->conf->ssl_certificate->lengths
-                                     || u->conf->ssl_certificate_key->lengths))
+    if (u->conf->ssl_certificate
+        && u->conf->ssl_certificate->value.len
+        && (u->conf->ssl_certificate->lengths
+            || u->conf->ssl_certificate_key->lengths))
     {
         if (ngx_http_upstream_ssl_certificate(r, u, c) != NGX_OK) {
             ngx_http_upstream_finalize_request(r, u,
@@ -2655,7 +2653,7 @@
 {
     ngx_int_t                  status;
     ngx_uint_t                 i;
-    ngx_table_elt_t           *h;
+    ngx_table_elt_t           *h, *ho, **ph;
     ngx_http_err_page_t       *err_page;
     ngx_http_core_loc_conf_t  *clcf;
 
@@ -2684,23 +2682,36 @@
             if (status == NGX_HTTP_UNAUTHORIZED
                 && u->headers_in.www_authenticate)
             {
-                h = ngx_list_push(&r->headers_out.headers);
+                h = u->headers_in.www_authenticate;
+                ph = &r->headers_out.www_authenticate;
 
-                if (h == NULL) {
-                    ngx_http_upstream_finalize_request(r, u,
+                while (h) {
+                    ho = ngx_list_push(&r->headers_out.headers);
+
+                    if (ho == NULL) {
+                        ngx_http_upstream_finalize_request(r, u,
                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
-                    return NGX_OK;
+                        return NGX_OK;
+                    }
+
+                    *ho = *h;
+                    ho->next = NULL;
+
+                    *ph = ho;
+                    ph = &ho->next;
+
+                    h = h->next;
                 }
-
-                *h = *u->headers_in.www_authenticate;
-
-                r->headers_out.www_authenticate = h;
             }
 
 #if (NGX_HTTP_CACHE)
 
             if (r->cache) {
 
+                if (u->headers_in.no_cache || u->headers_in.expired) {
+                    u->cacheable = 0;
+                }
+
                 if (u->cacheable) {
                     time_t  valid;
 
@@ -2795,6 +2806,10 @@
 
     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
 
+    if (u->headers_in.no_cache || u->headers_in.expired) {
+        u->cacheable = 0;
+    }
+
     if (u->headers_in.x_accel_redirect
         && !(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT))
     {
@@ -2815,6 +2830,10 @@
                 i = 0;
             }
 
+            if (h[i].hash == 0) {
+                continue;
+            }
+
             hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash,
                                h[i].lowcase_key, h[i].key.len);
 
@@ -2868,6 +2887,10 @@
             i = 0;
         }
 
+        if (h[i].hash == 0) {
+            continue;
+        }
+
         if (ngx_hash_find(&u->conf->hide_headers_hash, h[i].hash,
                           h[i].lowcase_key, h[i].key.len))
         {
@@ -4619,10 +4642,36 @@
 
     ph = (ngx_table_elt_t **) ((char *) &r->upstream->headers_in + offset);
 
-    if (*ph == NULL) {
-        *ph = h;
+    if (*ph) {
+        ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
+                      "upstream sent duplicate header line: \"%V: %V\", "
+                      "previous value: \"%V: %V\", ignored",
+                      &h->key, &h->value,
+                      &(*ph)->key, &(*ph)->value);
+        h->hash = 0;
+        return NGX_OK;
     }
 
+    *ph = h;
+    h->next = NULL;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_upstream_process_multi_header_lines(ngx_http_request_t *r,
+    ngx_table_elt_t *h, ngx_uint_t offset)
+{
+    ngx_table_elt_t  **ph;
+
+    ph = (ngx_table_elt_t **) ((char *) &r->upstream->headers_in + offset);
+
+    while (*ph) { ph = &(*ph)->next; }
+
+    *ph = h;
+    h->next = NULL;
+
     return NGX_OK;
 }
 
@@ -4643,9 +4692,34 @@
 
     u = r->upstream;
 
+    if (u->headers_in.content_length) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "upstream sent duplicate header line: \"%V: %V\", "
+                      "previous value: \"%V: %V\"",
+                      &h->key, &h->value,
+                      &u->headers_in.content_length->key,
+                      &u->headers_in.content_length->value);
+        return NGX_HTTP_UPSTREAM_INVALID_HEADER;
+    }
+
+    if (u->headers_in.transfer_encoding) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "upstream sent \"Content-Length\" and "
+                      "\"Transfer-Encoding\" headers at the same time");
+        return NGX_HTTP_UPSTREAM_INVALID_HEADER;
+    }
+
+    h->next = NULL;
     u->headers_in.content_length = h;
     u->headers_in.content_length_n = ngx_atoof(h->value.data, h->value.len);
 
+    if (u->headers_in.content_length_n == NGX_ERROR) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "upstream sent invalid \"Content-Length\" header: "
+                      "\"%V: %V\"", &h->key, &h->value);
+        return NGX_HTTP_UPSTREAM_INVALID_HEADER;
+    }
+
     return NGX_OK;
 }
 
@@ -4658,6 +4732,18 @@
 
     u = r->upstream;
 
+    if (u->headers_in.last_modified) {
+        ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
+                      "upstream sent duplicate header line: \"%V: %V\", "
+                      "previous value: \"%V: %V\", ignored",
+                      &h->key, &h->value,
+                      &u->headers_in.last_modified->key,
+                      &u->headers_in.last_modified->value);
+        h->hash = 0;
+        return NGX_OK;
+    }
+
+    h->next = NULL;
     u->headers_in.last_modified = h;
     u->headers_in.last_modified_time = ngx_parse_http_time(h->value.data,
                                                            h->value.len);
@@ -4670,26 +4756,16 @@
 ngx_http_upstream_process_set_cookie(ngx_http_request_t *r, ngx_table_elt_t *h,
     ngx_uint_t offset)
 {
-    ngx_array_t           *pa;
     ngx_table_elt_t      **ph;
     ngx_http_upstream_t   *u;
 
     u = r->upstream;
-    pa = &u->headers_in.cookies;
+    ph = &u->headers_in.set_cookie;
 
-    if (pa->elts == NULL) {
-        if (ngx_array_init(pa, r->pool, 1, sizeof(ngx_table_elt_t *)) != NGX_OK)
-        {
-            return NGX_ERROR;
-        }
-    }
-
-    ph = ngx_array_push(pa);
-    if (ph == NULL) {
-        return NGX_ERROR;
-    }
+    while (*ph) { ph = &(*ph)->next; }
 
     *ph = h;
+    h->next = NULL;
 
 #if (NGX_HTTP_CACHE)
     if (!(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_SET_COOKIE)) {
@@ -4705,26 +4781,16 @@
 ngx_http_upstream_process_cache_control(ngx_http_request_t *r,
     ngx_table_elt_t *h, ngx_uint_t offset)
 {
-    ngx_array_t          *pa;
-    ngx_table_elt_t     **ph;
-    ngx_http_upstream_t  *u;
+    ngx_table_elt_t      **ph;
+    ngx_http_upstream_t   *u;
 
     u = r->upstream;
-    pa = &u->headers_in.cache_control;
+    ph = &u->headers_in.cache_control;
 
-    if (pa->elts == NULL) {
-        if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK)
-        {
-            return NGX_ERROR;
-        }
-    }
-
-    ph = ngx_array_push(pa);
-    if (ph == NULL) {
-        return NGX_ERROR;
-    }
+    while (*ph) { ph = &(*ph)->next; }
 
     *ph = h;
+    h->next = NULL;
 
 #if (NGX_HTTP_CACHE)
     {
@@ -4739,18 +4805,18 @@
         return NGX_OK;
     }
 
-    if (r->cache->valid_sec != 0 && u->headers_in.x_accel_expires != NULL) {
-        return NGX_OK;
-    }
-
     start = h->value.data;
     last = start + h->value.len;
 
+    if (r->cache->valid_sec != 0 && u->headers_in.x_accel_expires != NULL) {
+        goto extensions;
+    }
+
     if (ngx_strlcasestrn(start, last, (u_char *) "no-cache", 8 - 1) != NULL
         || ngx_strlcasestrn(start, last, (u_char *) "no-store", 8 - 1) != NULL
         || ngx_strlcasestrn(start, last, (u_char *) "private", 7 - 1) != NULL)
     {
-        u->cacheable = 0;
+        u->headers_in.no_cache = 1;
         return NGX_OK;
     }
 
@@ -4780,13 +4846,16 @@
         }
 
         if (n == 0) {
-            u->cacheable = 0;
+            u->headers_in.no_cache = 1;
             return NGX_OK;
         }
 
         r->cache->valid_sec = ngx_time() + n;
+        u->headers_in.expired = 0;
     }
 
+extensions:
+
     p = ngx_strlcasestrn(start, last, (u_char *) "stale-while-revalidate=",
                          23 - 1);
 
@@ -4846,7 +4915,20 @@
     ngx_http_upstream_t  *u;
 
     u = r->upstream;
+
+    if (u->headers_in.expires) {
+        ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
+                      "upstream sent duplicate header line: \"%V: %V\", "
+                      "previous value: \"%V: %V\", ignored",
+                      &h->key, &h->value,
+                      &u->headers_in.expires->key,
+                      &u->headers_in.expires->value);
+        h->hash = 0;
+        return NGX_OK;
+    }
+
     u->headers_in.expires = h;
+    h->next = NULL;
 
 #if (NGX_HTTP_CACHE)
     {
@@ -4867,7 +4949,7 @@
     expires = ngx_parse_http_time(h->value.data, h->value.len);
 
     if (expires == NGX_ERROR || expires < ngx_time()) {
-        u->cacheable = 0;
+        u->headers_in.expired = 1;
         return NGX_OK;
     }
 
@@ -4886,7 +4968,20 @@
     ngx_http_upstream_t  *u;
 
     u = r->upstream;
+
+    if (u->headers_in.x_accel_expires) {
+        ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
+                      "upstream sent duplicate header line: \"%V: %V\", "
+                      "previous value: \"%V: %V\", ignored",
+                      &h->key, &h->value,
+                      &u->headers_in.x_accel_expires->key,
+                      &u->headers_in.x_accel_expires->value);
+        h->hash = 0;
+        return NGX_OK;
+    }
+
     u->headers_in.x_accel_expires = h;
+    h->next = NULL;
 
 #if (NGX_HTTP_CACHE)
     {
@@ -4918,6 +5013,8 @@
 
         default:
             r->cache->valid_sec = ngx_time() + n;
+            u->headers_in.no_cache = 0;
+            u->headers_in.expired = 0;
             return NGX_OK;
         }
     }
@@ -4929,6 +5026,8 @@
 
     if (n != NGX_ERROR) {
         r->cache->valid_sec = n;
+        u->headers_in.no_cache = 0;
+        u->headers_in.expired = 0;
     }
     }
 #endif
@@ -4945,7 +5044,20 @@
     ngx_http_upstream_t  *u;
 
     u = r->upstream;
+
+    if (u->headers_in.x_accel_limit_rate) {
+        ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
+                      "upstream sent duplicate header line: \"%V: %V\", "
+                      "previous value: \"%V: %V\", ignored",
+                      &h->key, &h->value,
+                      &u->headers_in.x_accel_limit_rate->key,
+                      &u->headers_in.x_accel_limit_rate->value);
+        h->hash = 0;
+        return NGX_OK;
+    }
+
     u->headers_in.x_accel_limit_rate = h;
+    h->next = NULL;
 
     if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_LIMIT_RATE) {
         return NGX_OK;
@@ -5004,7 +5116,11 @@
 ngx_http_upstream_process_charset(ngx_http_request_t *r, ngx_table_elt_t *h,
     ngx_uint_t offset)
 {
-    if (r->upstream->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_CHARSET) {
+    ngx_http_upstream_t  *u;
+
+    u = r->upstream;
+
+    if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_CHARSET) {
         return NGX_OK;
     }
 
@@ -5018,13 +5134,22 @@
 ngx_http_upstream_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h,
     ngx_uint_t offset)
 {
-    r->upstream->headers_in.connection = h;
+    ngx_table_elt_t      **ph;
+    ngx_http_upstream_t   *u;
+
+    u = r->upstream;
+    ph = &u->headers_in.connection;
+
+    while (*ph) { ph = &(*ph)->next; }
+
+    *ph = h;
+    h->next = NULL;
 
     if (ngx_strlcasestrn(h->value.data, h->value.data + h->value.len,
                          (u_char *) "close", 5 - 1)
         != NULL)
     {
-        r->upstream->headers_in.connection_close = 1;
+        u->headers_in.connection_close = 1;
     }
 
     return NGX_OK;
@@ -5035,13 +5160,40 @@
 ngx_http_upstream_process_transfer_encoding(ngx_http_request_t *r,
     ngx_table_elt_t *h, ngx_uint_t offset)
 {
-    r->upstream->headers_in.transfer_encoding = h;
+    ngx_http_upstream_t  *u;
 
-    if (ngx_strlcasestrn(h->value.data, h->value.data + h->value.len,
-                         (u_char *) "chunked", 7 - 1)
-        != NULL)
+    u = r->upstream;
+
+    if (u->headers_in.transfer_encoding) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "upstream sent duplicate header line: \"%V: %V\", "
+                      "previous value: \"%V: %V\"",
+                      &h->key, &h->value,
+                      &u->headers_in.transfer_encoding->key,
+                      &u->headers_in.transfer_encoding->value);
+        return NGX_HTTP_UPSTREAM_INVALID_HEADER;
+    }
+
+    if (u->headers_in.content_length) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "upstream sent \"Content-Length\" and "
+                      "\"Transfer-Encoding\" headers at the same time");
+        return NGX_HTTP_UPSTREAM_INVALID_HEADER;
+    }
+
+    u->headers_in.transfer_encoding = h;
+    h->next = NULL;
+
+    if (h->value.len == 7
+        && ngx_strncasecmp(h->value.data, (u_char *) "chunked", 7) == 0)
     {
-        r->upstream->headers_in.chunked = 1;
+        u->headers_in.chunked = 1;
+
+    } else {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "upstream sent unknown \"Transfer-Encoding\": \"%V\"",
+                      &h->value);
+        return NGX_HTTP_UPSTREAM_INVALID_HEADER;
     }
 
     return NGX_OK;
@@ -5052,29 +5204,74 @@
 ngx_http_upstream_process_vary(ngx_http_request_t *r,
     ngx_table_elt_t *h, ngx_uint_t offset)
 {
-    ngx_http_upstream_t  *u;
+    ngx_table_elt_t      **ph;
+    ngx_http_upstream_t   *u;
 
     u = r->upstream;
-    u->headers_in.vary = h;
+    ph = &u->headers_in.vary;
+
+    while (*ph) { ph = &(*ph)->next; }
+
+    *ph = h;
+    h->next = NULL;
 
 #if (NGX_HTTP_CACHE)
+    {
+    u_char     *p;
+    size_t      len;
+    ngx_str_t   vary;
 
     if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_VARY) {
         return NGX_OK;
     }
 
-    if (r->cache == NULL) {
+    if (r->cache == NULL || !u->cacheable) {
         return NGX_OK;
     }
 
-    if (h->value.len > NGX_HTTP_CACHE_VARY_LEN
-        || (h->value.len == 1 && h->value.data[0] == '*'))
-    {
+    if (h->value.len == 1 && h->value.data[0] == '*') {
+        u->cacheable = 0;
+        return NGX_OK;
+    }
+
+    if (u->headers_in.vary->next) {
+
+        len = 0;
+
+        for (h = u->headers_in.vary; h; h = h->next) {
+            len += h->value.len + 2;
+        }
+
+        len -= 2;
+
+        p = ngx_pnalloc(r->pool, len);
+        if (p == NULL) {
+            return NGX_ERROR;
+        }
+
+        vary.len = len;
+        vary.data = p;
+
+        for (h = u->headers_in.vary; h; h = h->next) {
+            p = ngx_copy(p, h->value.data, h->value.len);
+
+            if (h->next == NULL) {
+                break;
+            }
+
+            *p++ = ','; *p++ = ' ';
+        }
+
+    } else {
+        vary = h->value;
+    }
+
+    if (vary.len > NGX_HTTP_CACHE_VARY_LEN) {
         u->cacheable = 0;
     }
 
-    r->cache->vary = h->value;
-
+    r->cache->vary = vary;
+    }
 #endif
 
     return NGX_OK;
@@ -5097,6 +5294,7 @@
     if (offset) {
         ph = (ngx_table_elt_t **) ((char *) &r->headers_out + offset);
         *ph = ho;
+        ho->next = NULL;
     }
 
     return NGX_OK;
@@ -5107,18 +5305,8 @@
 ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r,
     ngx_table_elt_t *h, ngx_uint_t offset)
 {
-    ngx_array_t      *pa;
     ngx_table_elt_t  *ho, **ph;
 
-    pa = (ngx_array_t *) ((char *) &r->headers_out + offset);
-
-    if (pa->elts == NULL) {
-        if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK)
-        {
-            return NGX_ERROR;
-        }
-    }
-
     ho = ngx_list_push(&r->headers_out.headers);
     if (ho == NULL) {
         return NGX_ERROR;
@@ -5126,12 +5314,12 @@
 
     *ho = *h;
 
-    ph = ngx_array_push(pa);
-    if (ph == NULL) {
-        return NGX_ERROR;
-    }
+    ph = (ngx_table_elt_t **) ((char *) &r->headers_out + offset);
+
+    while (*ph) { ph = &(*ph)->next; }
 
     *ph = ho;
+    ho->next = NULL;
 
     return NGX_OK;
 }
@@ -5201,6 +5389,7 @@
     }
 
     *ho = *h;
+    ho->next = NULL;
 
     r->headers_out.last_modified = ho;
     r->headers_out.last_modified_time =
@@ -5223,6 +5412,7 @@
     }
 
     *ho = *h;
+    ho->next = NULL;
 
     if (r->upstream->rewrite_redirect) {
         rc = r->upstream->rewrite_redirect(r, ho, 0);
@@ -5268,6 +5458,7 @@
     }
 
     *ho = *h;
+    ho->next = NULL;
 
     if (r->upstream->rewrite_redirect) {
 
@@ -5313,6 +5504,7 @@
     }
 
     *ho = *h;
+    ho->next = NULL;
 
     if (r->upstream->rewrite_cookie) {
         rc = r->upstream->rewrite_cookie(r, ho);
@@ -5366,6 +5558,7 @@
     }
 
     *ho = *h;
+    ho->next = NULL;
 
     r->headers_out.accept_ranges = ho;
 
@@ -5373,29 +5566,6 @@
 }
 
 
-#if (NGX_HTTP_GZIP || NGX_COMPAT)
-
-static ngx_int_t
-ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r,
-    ngx_table_elt_t *h, ngx_uint_t offset)
-{
-    ngx_table_elt_t  *ho;
-
-    ho = ngx_list_push(&r->headers_out.headers);
-    if (ho == NULL) {
-        return NGX_ERROR;
-    }
-
-    *ho = *h;
-
-    r->headers_out.content_encoding = ho;
-
-    return NGX_OK;
-}
-
-#endif
-
-
 static ngx_int_t
 ngx_http_upstream_add_variables(ngx_conf_t *cf)
 {
@@ -5707,7 +5877,7 @@
         return NGX_OK;
     }
 
-    return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
+    return ngx_http_variable_unknown_header(r, v, (ngx_str_t *) data,
                                          &r->upstream->headers_in.headers.part,
                                          sizeof("upstream_http_") - 1);
 }
@@ -5722,7 +5892,7 @@
         return NGX_OK;
     }
 
-    return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
+    return ngx_http_variable_unknown_header(r, v, (ngx_str_t *) data,
                                         &r->upstream->headers_in.trailers.part,
                                         sizeof("upstream_trailer_") - 1);
 }
@@ -5744,9 +5914,9 @@
     s.len = name->len - (sizeof("upstream_cookie_") - 1);
     s.data = name->data + sizeof("upstream_cookie_") - 1;
 
-    if (ngx_http_parse_set_cookie_lines(&r->upstream->headers_in.cookies,
+    if (ngx_http_parse_set_cookie_lines(r, r->upstream->headers_in.set_cookie,
                                         &s, &cookie)
-        == NGX_DECLINED)
+        == NULL)
     {
         v->not_found = 1;
         return NGX_OK;
diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h
index b6cef95..22af805 100644
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -281,23 +281,21 @@
 
     ngx_table_elt_t                 *last_modified;
     ngx_table_elt_t                 *location;
-    ngx_table_elt_t                 *accept_ranges;
+    ngx_table_elt_t                 *refresh;
     ngx_table_elt_t                 *www_authenticate;
     ngx_table_elt_t                 *transfer_encoding;
     ngx_table_elt_t                 *vary;
 
-#if (NGX_HTTP_GZIP || NGX_COMPAT)
-    ngx_table_elt_t                 *content_encoding;
-#endif
-
-    ngx_array_t                      cache_control;
-    ngx_array_t                      cookies;
+    ngx_table_elt_t                 *cache_control;
+    ngx_table_elt_t                 *set_cookie;
 
     off_t                            content_length_n;
     time_t                           last_modified_time;
 
     unsigned                         connection_close:1;
     unsigned                         chunked:1;
+    unsigned                         no_cache:1;
+    unsigned                         expired:1;
 } ngx_http_upstream_headers_in_t;
 
 
diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c
index 410e2bd..141495c 100644
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -27,8 +27,6 @@
 
 static ngx_int_t ngx_http_variable_cookies(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
-static ngx_int_t ngx_http_variable_headers(ngx_http_request_t *r,
-    ngx_http_variable_value_t *v, uintptr_t data);
 static ngx_int_t ngx_http_variable_headers_internal(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data, u_char sep);
 
@@ -178,12 +176,12 @@
 #endif
 
 #if (NGX_HTTP_X_FORWARDED_FOR || NGX_COMPAT)
-    { ngx_string("http_x_forwarded_for"), NULL, ngx_http_variable_headers,
+    { ngx_string("http_x_forwarded_for"), NULL, ngx_http_variable_header,
       offsetof(ngx_http_request_t, headers_in.x_forwarded_for), 0, 0 },
 #endif
 
     { ngx_string("http_cookie"), NULL, ngx_http_variable_cookies,
-      offsetof(ngx_http_request_t, headers_in.cookies), 0, 0 },
+      offsetof(ngx_http_request_t, headers_in.cookie), 0, 0 },
 
     { ngx_string("content_length"), NULL, ngx_http_variable_content_length,
       0, 0, 0 },
@@ -327,10 +325,10 @@
     { ngx_string("sent_http_transfer_encoding"), NULL,
       ngx_http_variable_sent_transfer_encoding, 0, 0, 0 },
 
-    { ngx_string("sent_http_cache_control"), NULL, ngx_http_variable_headers,
+    { ngx_string("sent_http_cache_control"), NULL, ngx_http_variable_header,
       offsetof(ngx_http_request_t, headers_out.cache_control), 0, 0 },
 
-    { ngx_string("sent_http_link"), NULL, ngx_http_variable_headers,
+    { ngx_string("sent_http_link"), NULL, ngx_http_variable_header,
       offsetof(ngx_http_request_t, headers_out.link), 0, 0 },
 
     { ngx_string("limit_rate"), ngx_http_variable_set_limit_rate,
@@ -807,22 +805,7 @@
 ngx_http_variable_header(ngx_http_request_t *r, ngx_http_variable_value_t *v,
     uintptr_t data)
 {
-    ngx_table_elt_t  *h;
-
-    h = *(ngx_table_elt_t **) ((char *) r + data);
-
-    if (h) {
-        v->len = h->value.len;
-        v->valid = 1;
-        v->no_cacheable = 0;
-        v->not_found = 0;
-        v->data = h->value.data;
-
-    } else {
-        v->not_found = 1;
-    }
-
-    return NGX_OK;
+    return ngx_http_variable_headers_internal(r, v, data, ',');
 }
 
 
@@ -835,37 +818,24 @@
 
 
 static ngx_int_t
-ngx_http_variable_headers(ngx_http_request_t *r,
-    ngx_http_variable_value_t *v, uintptr_t data)
-{
-    return ngx_http_variable_headers_internal(r, v, data, ',');
-}
-
-
-static ngx_int_t
 ngx_http_variable_headers_internal(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data, u_char sep)
 {
-    size_t             len;
-    u_char            *p, *end;
-    ngx_uint_t         i, n;
-    ngx_array_t       *a;
-    ngx_table_elt_t  **h;
+    size_t            len;
+    u_char           *p;
+    ngx_table_elt_t  *h, *th;
 
-    a = (ngx_array_t *) ((char *) r + data);
-
-    n = a->nelts;
-    h = a->elts;
+    h = *(ngx_table_elt_t **) ((char *) r + data);
 
     len = 0;
 
-    for (i = 0; i < n; i++) {
+    for (th = h; th; th = th->next) {
 
-        if (h[i]->hash == 0) {
+        if (th->hash == 0) {
             continue;
         }
 
-        len += h[i]->value.len + 2;
+        len += th->value.len + 2;
     }
 
     if (len == 0) {
@@ -879,9 +849,9 @@
     v->no_cacheable = 0;
     v->not_found = 0;
 
-    if (n == 1) {
-        v->len = (*h)->value.len;
-        v->data = (*h)->value.data;
+    if (h->next == NULL) {
+        v->len = h->value.len;
+        v->data = h->value.data;
 
         return NGX_OK;
     }
@@ -894,17 +864,15 @@
     v->len = len;
     v->data = p;
 
-    end = p + len;
+    for (th = h; th; th = th->next) {
 
-    for (i = 0; /* void */ ; i++) {
-
-        if (h[i]->hash == 0) {
+        if (th->hash == 0) {
             continue;
         }
 
-        p = ngx_copy(p, h[i]->value.data, h[i]->value.len);
+        p = ngx_copy(p, th->value.data, th->value.len);
 
-        if (p == end) {
+        if (th->next == NULL) {
             break;
         }
 
@@ -919,7 +887,7 @@
 ngx_http_variable_unknown_header_in(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data)
 {
-    return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
+    return ngx_http_variable_unknown_header(r, v, (ngx_str_t *) data,
                                             &r->headers_in.headers.part,
                                             sizeof("http_") - 1);
 }
@@ -929,7 +897,7 @@
 ngx_http_variable_unknown_header_out(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data)
 {
-    return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
+    return ngx_http_variable_unknown_header(r, v, (ngx_str_t *) data,
                                             &r->headers_out.headers.part,
                                             sizeof("sent_http_") - 1);
 }
@@ -939,19 +907,26 @@
 ngx_http_variable_unknown_trailer_out(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data)
 {
-    return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
+    return ngx_http_variable_unknown_header(r, v, (ngx_str_t *) data,
                                             &r->headers_out.trailers.part,
                                             sizeof("sent_trailer_") - 1);
 }
 
 
 ngx_int_t
-ngx_http_variable_unknown_header(ngx_http_variable_value_t *v, ngx_str_t *var,
+ngx_http_variable_unknown_header(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, ngx_str_t *var,
     ngx_list_part_t *part, size_t prefix)
 {
-    u_char            ch;
+    u_char           *p, ch;
+    size_t            len;
     ngx_uint_t        i, n;
-    ngx_table_elt_t  *header;
+    ngx_table_elt_t  *header, *h, **ph;
+
+    ph = &h;
+#if (NGX_SUPPRESS_WARN)
+    len = 0;
+#endif
 
     header = part->elts;
 
@@ -971,7 +946,11 @@
             continue;
         }
 
-        for (n = 0; n + prefix < var->len && n < header[i].key.len; n++) {
+        if (header[i].key.len != var->len - prefix) {
+            continue;
+        }
+
+        for (n = 0; n < var->len - prefix; n++) {
             ch = header[i].key.data[n];
 
             if (ch >= 'A' && ch <= 'Z') {
@@ -986,18 +965,59 @@
             }
         }
 
-        if (n + prefix == var->len && n == header[i].key.len) {
-            v->len = header[i].value.len;
-            v->valid = 1;
-            v->no_cacheable = 0;
-            v->not_found = 0;
-            v->data = header[i].value.data;
-
-            return NGX_OK;
+        if (n != var->len - prefix) {
+            continue;
         }
+
+        len += header[i].value.len + 2;
+
+        *ph = &header[i];
+        ph = &header[i].next;
     }
 
-    v->not_found = 1;
+    *ph = NULL;
+
+    if (h == NULL) {
+        v->not_found = 1;
+        return NGX_OK;
+    }
+
+    len -= 2;
+
+    if (h->next == NULL) {
+
+        v->len = h->value.len;
+        v->valid = 1;
+        v->no_cacheable = 0;
+        v->not_found = 0;
+        v->data = h->value.data;
+
+        return NGX_OK;
+    }
+
+    p = ngx_pnalloc(r->pool, len);
+    if (p == NULL) {
+        return NGX_ERROR;
+    }
+
+    v->len = len;
+    v->valid = 1;
+    v->no_cacheable = 0;
+    v->not_found = 0;
+    v->data = p;
+
+    for ( ;; ) {
+
+        p = ngx_copy(p, h->value.data, h->value.len);
+
+        if (h->next == NULL) {
+            break;
+        }
+
+        *p++ = ','; *p++ = ' ';
+
+        h = h->next;
+    }
 
     return NGX_OK;
 }
@@ -1050,8 +1070,8 @@
     s.len = name->len - (sizeof("cookie_") - 1);
     s.data = name->data + sizeof("cookie_") - 1;
 
-    if (ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &s, &cookie)
-        == NGX_DECLINED)
+    if (ngx_http_parse_multi_header_lines(r, r->headers_in.cookie, &s, &cookie)
+        == NULL)
     {
         v->not_found = 1;
         return NGX_OK;
@@ -1879,7 +1899,7 @@
 
     ngx_str_set(&name, "sent_http_location");
 
-    return ngx_http_variable_unknown_header(v, &name,
+    return ngx_http_variable_unknown_header(r, v, &name,
                                             &r->headers_out.headers.part,
                                             sizeof("sent_http_") - 1);
 }
diff --git a/src/http/ngx_http_variables.h b/src/http/ngx_http_variables.h
index f3f7f3c..6a661a2 100644
--- a/src/http/ngx_http_variables.h
+++ b/src/http/ngx_http_variables.h
@@ -57,8 +57,9 @@
 ngx_http_variable_value_t *ngx_http_get_variable(ngx_http_request_t *r,
     ngx_str_t *name, ngx_uint_t key);
 
-ngx_int_t ngx_http_variable_unknown_header(ngx_http_variable_value_t *v,
-    ngx_str_t *var, ngx_list_part_t *part, size_t prefix);
+ngx_int_t ngx_http_variable_unknown_header(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, ngx_str_t *var, ngx_list_part_t *part,
+    size_t prefix);
 
 
 #if (NGX_PCRE)
diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c
index 932f26d..89ab49e 100644
--- a/src/http/ngx_http_write_filter_module.c
+++ b/src/http/ngx_http_write_filter_module.c
@@ -227,7 +227,8 @@
 
     if (size == 0
         && !(c->buffered & NGX_LOWLEVEL_BUFFERED)
-        && !(last && c->need_last_buf))
+        && !(last && c->need_last_buf)
+        && !(flush && c->need_flush_buf))
     {
         if (last || flush || sync) {
             for (cl = r->out; cl; /* void */) {
diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h
index 70ee287..4e25293 100644
--- a/src/http/v2/ngx_http_v2.h
+++ b/src/http/v2/ngx_http_v2.h
@@ -153,12 +153,12 @@
     ngx_queue_t                      dependencies;
     ngx_queue_t                      closed;
 
+    ngx_uint_t                       closed_nodes;
     ngx_uint_t                       last_sid;
     ngx_uint_t                       last_push;
 
     time_t                           lingering_time;
 
-    unsigned                         closed_nodes:8;
     unsigned                         settings_ack:1;
     unsigned                         table_update:1;
     unsigned                         blocked:1;
diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c
index 80e5311..bc31265 100644
--- a/src/http/v2/ngx_http_v2_filter_module.c
+++ b/src/http/v2/ngx_http_v2_filter_module.c
@@ -674,6 +674,7 @@
 
     fc->send_chain = ngx_http_v2_send_chain;
     fc->need_last_buf = 1;
+    fc->need_flush_buf = 1;
 
     return ngx_http_v2_filter_send(fc, stream);
 }
@@ -682,14 +683,14 @@
 static ngx_int_t
 ngx_http_v2_push_resources(ngx_http_request_t *r)
 {
-    u_char                     *start, *end, *last;
-    ngx_int_t                   rc;
-    ngx_str_t                   path;
-    ngx_uint_t                  i, push;
-    ngx_table_elt_t           **h;
-    ngx_http_v2_loc_conf_t     *h2lcf;
-    ngx_http_complex_value_t   *pushes;
-    ngx_str_t                   binary[NGX_HTTP_V2_PUSH_HEADERS];
+    u_char                    *start, *end, *last;
+    ngx_int_t                  rc;
+    ngx_str_t                  path;
+    ngx_uint_t                 i, push;
+    ngx_table_elt_t           *h;
+    ngx_http_v2_loc_conf_t    *h2lcf;
+    ngx_http_complex_value_t  *pushes;
+    ngx_str_t                  binary[NGX_HTTP_V2_PUSH_HEADERS];
 
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "http2 push resources");
@@ -733,15 +734,13 @@
         return NGX_OK;
     }
 
-    h = r->headers_out.link.elts;
-
-    for (i = 0; i < r->headers_out.link.nelts; i++) {
+    for (h = r->headers_out.link; h; h = h->next) {
 
         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "http2 parse link: \"%V\"", &h[i]->value);
+                       "http2 parse link: \"%V\"", &h->value);
 
-        start = h[i]->value.data;
-        end = h[i]->value.data + h[i]->value.len;
+        start = h->value.data;
+        end = h->value.data + h->value.len;
 
     next_link:
 
@@ -1824,7 +1823,11 @@
 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) {
+    ngx_connection_t  *c;
+
+    c = stream->connection->connection;
+
+    if (stream->queued == 0 && !c->buffered) {
         fc->buffered &= ~NGX_HTTP_V2_BUFFERED;
         return NGX_OK;
     }
diff --git a/src/ngx_modules.c b/src/ngx_modules.c
index 2a4a6d0..a847e9e 100644
--- a/src/ngx_modules.c
+++ b/src/ngx_modules.c
@@ -1,6 +1,6 @@
 
 /*
- * Copyright (C) Google Inc.
+ * Copyright (C) 2015-2022 Google LLC
  */
 
 
diff --git a/src/ngx_modules.h b/src/ngx_modules.h
index 048b45b..e0004e2 100644
--- a/src/ngx_modules.h
+++ b/src/ngx_modules.h
@@ -1,6 +1,6 @@
 
 /*
- * Copyright (C) Google Inc.
+ * Copyright (C) 2015-2022 Google LLC
  */
 
 
diff --git a/src/os/unix/ngx_linux_config.h b/src/os/unix/ngx_linux_config.h
index 3036cae..88fef47 100644
--- a/src/os/unix/ngx_linux_config.h
+++ b/src/os/unix/ngx_linux_config.h
@@ -103,6 +103,10 @@
 #include <linux/capability.h>
 #endif
 
+#if (NGX_HAVE_UDP_SEGMENT)
+#include <netinet/udp.h>
+#endif
+
 
 #define NGX_LISTEN_BACKLOG        511
 
diff --git a/src/os/unix/ngx_readv_chain.c b/src/os/unix/ngx_readv_chain.c
index b1ae4b5..370a401 100644
--- a/src/os/unix/ngx_readv_chain.c
+++ b/src/os/unix/ngx_readv_chain.c
@@ -55,7 +55,9 @@
 
 #if (NGX_HAVE_EPOLLRDHUP)
 
-    if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {
+    if ((ngx_event_flags & NGX_USE_EPOLL_EVENT)
+        && ngx_use_epoll_rdhup)
+    {
         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
                        "readv: eof:%d, avail:%d",
                        rev->pending_eof, rev->available);
diff --git a/src/os/unix/ngx_recv.c b/src/os/unix/ngx_recv.c
index ddfae4d..cc04a5f 100644
--- a/src/os/unix/ngx_recv.c
+++ b/src/os/unix/ngx_recv.c
@@ -52,7 +52,9 @@
 
 #if (NGX_HAVE_EPOLLRDHUP)
 
-    if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {
+    if ((ngx_event_flags & NGX_USE_EPOLL_EVENT)
+        && ngx_use_epoll_rdhup)
+    {
         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
                        "recv: eof:%d, avail:%d",
                        rev->pending_eof, rev->available);
diff --git a/src/os/unix/ngx_udp_sendmsg_chain.c b/src/os/unix/ngx_udp_sendmsg_chain.c
index 3d1d6dd..e9e6f70 100644
--- a/src/os/unix/ngx_udp_sendmsg_chain.c
+++ b/src/os/unix/ngx_udp_sendmsg_chain.c
@@ -12,7 +12,7 @@
 
 static ngx_chain_t *ngx_udp_output_chain_to_iovec(ngx_iovec_t *vec,
     ngx_chain_t *in, ngx_log_t *log);
-static ssize_t ngx_sendmsg(ngx_connection_t *c, ngx_iovec_t *vec);
+static ssize_t ngx_sendmsg_vec(ngx_connection_t *c, ngx_iovec_t *vec);
 
 
 ngx_chain_t *
@@ -88,7 +88,7 @@
 
         send += vec.size;
 
-        n = ngx_sendmsg(c, &vec);
+        n = ngx_sendmsg_vec(c, &vec);
 
         if (n == NGX_ERROR) {
             return NGX_CHAIN_ERROR;
@@ -204,24 +204,13 @@
 
 
 static ssize_t
-ngx_sendmsg(ngx_connection_t *c, ngx_iovec_t *vec)
+ngx_sendmsg_vec(ngx_connection_t *c, ngx_iovec_t *vec)
 {
-    ssize_t        n;
-    ngx_err_t      err;
-    struct msghdr  msg;
+    struct msghdr    msg;
 
-#if (NGX_HAVE_MSGHDR_MSG_CONTROL)
-
-#if (NGX_HAVE_IP_SENDSRCADDR)
-    u_char         msg_control[CMSG_SPACE(sizeof(struct in_addr))];
-#elif (NGX_HAVE_IP_PKTINFO)
-    u_char         msg_control[CMSG_SPACE(sizeof(struct in_pktinfo))];
-#endif
-
-#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
-    u_char         msg_control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
-#endif
-
+#if (NGX_HAVE_ADDRINFO_CMSG)
+    struct cmsghdr  *cmsg;
+    u_char           msg_control[CMSG_SPACE(sizeof(ngx_addrinfo_t))];
 #endif
 
     ngx_memzero(&msg, sizeof(struct msghdr));
@@ -234,88 +223,180 @@
     msg.msg_iov = vec->iovs;
     msg.msg_iovlen = vec->count;
 
-#if (NGX_HAVE_MSGHDR_MSG_CONTROL)
-
+#if (NGX_HAVE_ADDRINFO_CMSG)
     if (c->listening && c->listening->wildcard && c->local_sockaddr) {
 
+        msg.msg_control = msg_control;
+        msg.msg_controllen = sizeof(msg_control);
+        ngx_memzero(msg_control, sizeof(msg_control));
+
+        cmsg = CMSG_FIRSTHDR(&msg);
+
+        msg.msg_controllen = ngx_set_srcaddr_cmsg(cmsg, c->local_sockaddr);
+    }
+#endif
+
+    return ngx_sendmsg(c, &msg, 0);
+}
+
+
+#if (NGX_HAVE_ADDRINFO_CMSG)
+
+size_t
+ngx_set_srcaddr_cmsg(struct cmsghdr *cmsg, struct sockaddr *local_sockaddr)
+{
+    size_t                len;
+#if (NGX_HAVE_IP_SENDSRCADDR)
+    struct in_addr       *addr;
+    struct sockaddr_in   *sin;
+#elif (NGX_HAVE_IP_PKTINFO)
+    struct in_pktinfo    *pkt;
+    struct sockaddr_in   *sin;
+#endif
+
+#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
+    struct in6_pktinfo   *pkt6;
+    struct sockaddr_in6  *sin6;
+#endif
+
+
+#if (NGX_HAVE_IP_SENDSRCADDR) || (NGX_HAVE_IP_PKTINFO)
+
+    if (local_sockaddr->sa_family == AF_INET) {
+
+        cmsg->cmsg_level = IPPROTO_IP;
+
 #if (NGX_HAVE_IP_SENDSRCADDR)
 
-        if (c->local_sockaddr->sa_family == AF_INET) {
-            struct cmsghdr      *cmsg;
-            struct in_addr      *addr;
-            struct sockaddr_in  *sin;
+        cmsg->cmsg_type = IP_SENDSRCADDR;
+        cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
+        len = CMSG_SPACE(sizeof(struct in_addr));
 
-            msg.msg_control = &msg_control;
-            msg.msg_controllen = sizeof(msg_control);
+        sin = (struct sockaddr_in *) local_sockaddr;
 
-            cmsg = CMSG_FIRSTHDR(&msg);
-            cmsg->cmsg_level = IPPROTO_IP;
-            cmsg->cmsg_type = IP_SENDSRCADDR;
-            cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
-
-            sin = (struct sockaddr_in *) c->local_sockaddr;
-
-            addr = (struct in_addr *) CMSG_DATA(cmsg);
-            *addr = sin->sin_addr;
-        }
+        addr = (struct in_addr *) CMSG_DATA(cmsg);
+        *addr = sin->sin_addr;
 
 #elif (NGX_HAVE_IP_PKTINFO)
 
-        if (c->local_sockaddr->sa_family == AF_INET) {
-            struct cmsghdr      *cmsg;
-            struct in_pktinfo   *pkt;
-            struct sockaddr_in  *sin;
+        cmsg->cmsg_type = IP_PKTINFO;
+        cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+        len = CMSG_SPACE(sizeof(struct in_pktinfo));
 
-            msg.msg_control = &msg_control;
-            msg.msg_controllen = sizeof(msg_control);
+        sin = (struct sockaddr_in *) local_sockaddr;
 
-            cmsg = CMSG_FIRSTHDR(&msg);
-            cmsg->cmsg_level = IPPROTO_IP;
-            cmsg->cmsg_type = IP_PKTINFO;
-            cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+        pkt = (struct in_pktinfo *) CMSG_DATA(cmsg);
+        ngx_memzero(pkt, sizeof(struct in_pktinfo));
+        pkt->ipi_spec_dst = sin->sin_addr;
 
-            sin = (struct sockaddr_in *) c->local_sockaddr;
+#endif
+        return len;
+    }
 
-            pkt = (struct in_pktinfo *) CMSG_DATA(cmsg);
-            ngx_memzero(pkt, sizeof(struct in_pktinfo));
-            pkt->ipi_spec_dst = sin->sin_addr;
-        }
+#endif
+
+#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
+    if (local_sockaddr->sa_family == AF_INET6) {
+
+        cmsg->cmsg_level = IPPROTO_IPV6;
+        cmsg->cmsg_type = IPV6_PKTINFO;
+        cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+        len = CMSG_SPACE(sizeof(struct in6_pktinfo));
+
+        sin6 = (struct sockaddr_in6 *) local_sockaddr;
+
+        pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg);
+        ngx_memzero(pkt6, sizeof(struct in6_pktinfo));
+        pkt6->ipi6_addr = sin6->sin6_addr;
+
+        return len;
+    }
+#endif
+
+    return 0;
+}
+
+
+ngx_int_t
+ngx_get_srcaddr_cmsg(struct cmsghdr *cmsg, struct sockaddr *local_sockaddr)
+{
+
+#if (NGX_HAVE_IP_RECVDSTADDR)
+    struct in_addr       *addr;
+    struct sockaddr_in   *sin;
+#elif (NGX_HAVE_IP_PKTINFO)
+    struct in_pktinfo    *pkt;
+    struct sockaddr_in   *sin;
+#endif
+
+#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
+    struct in6_pktinfo   *pkt6;
+    struct sockaddr_in6  *sin6;
+#endif
+
+
+ #if (NGX_HAVE_IP_RECVDSTADDR)
+
+    if (cmsg->cmsg_level == IPPROTO_IP
+        && cmsg->cmsg_type == IP_RECVDSTADDR
+        && local_sockaddr->sa_family == AF_INET)
+    {
+        addr = (struct in_addr *) CMSG_DATA(cmsg);
+        sin = (struct sockaddr_in *) local_sockaddr;
+        sin->sin_addr = *addr;
+
+        return NGX_OK;
+    }
+
+#elif (NGX_HAVE_IP_PKTINFO)
+
+    if (cmsg->cmsg_level == IPPROTO_IP
+        && cmsg->cmsg_type == IP_PKTINFO
+        && local_sockaddr->sa_family == AF_INET)
+    {
+        pkt = (struct in_pktinfo *) CMSG_DATA(cmsg);
+        sin = (struct sockaddr_in *) local_sockaddr;
+        sin->sin_addr = pkt->ipi_addr;
+
+        return NGX_OK;
+    }
 
 #endif
 
 #if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
 
-        if (c->local_sockaddr->sa_family == AF_INET6) {
-            struct cmsghdr       *cmsg;
-            struct in6_pktinfo   *pkt6;
-            struct sockaddr_in6  *sin6;
+    if (cmsg->cmsg_level == IPPROTO_IPV6
+        && cmsg->cmsg_type == IPV6_PKTINFO
+        && local_sockaddr->sa_family == AF_INET6)
+    {
+        pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg);
+        sin6 = (struct sockaddr_in6 *) local_sockaddr;
+        sin6->sin6_addr = pkt6->ipi6_addr;
 
-            msg.msg_control = &msg_control6;
-            msg.msg_controllen = sizeof(msg_control6);
-
-            cmsg = CMSG_FIRSTHDR(&msg);
-            cmsg->cmsg_level = IPPROTO_IPV6;
-            cmsg->cmsg_type = IPV6_PKTINFO;
-            cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
-
-            sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
-
-            pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg);
-            ngx_memzero(pkt6, sizeof(struct in6_pktinfo));
-            pkt6->ipi6_addr = sin6->sin6_addr;
-        }
-
-#endif
+        return NGX_OK;
     }
 
 #endif
 
+    return NGX_DECLINED;
+}
+
+#endif
+
+
+ssize_t
+ngx_sendmsg(ngx_connection_t *c, struct msghdr *msg, int flags)
+{
+    ssize_t    n;
+    ngx_err_t  err;
+#if (NGX_DEBUG)
+    size_t      size;
+    ngx_uint_t  i;
+#endif
+
 eintr:
 
-    n = sendmsg(c->fd, &msg, 0);
-
-    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
-                   "sendmsg: %z of %uz", n, vec->size);
+    n = sendmsg(c->fd, msg, flags);
 
     if (n == -1) {
         err = ngx_errno;
@@ -338,5 +419,14 @@
         }
     }
 
+#if (NGX_DEBUG)
+    for (i = 0, size = 0; i < (size_t) msg->msg_iovlen; i++) {
+        size += msg->msg_iov[i].iov_len;
+    }
+
+    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+                   "sendmsg: %z of %uz", n, size);
+#endif
+
     return n;
 }
diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c
index 934e7d8..bd462ff 100644
--- a/src/stream/ngx_stream_proxy_module.c
+++ b/src/stream/ngx_stream_proxy_module.c
@@ -1069,8 +1069,10 @@
         }
     }
 
-    if (pscf->ssl_certificate && (pscf->ssl_certificate->lengths
-                                  || pscf->ssl_certificate_key->lengths))
+    if (pscf->ssl_certificate
+        && pscf->ssl_certificate->value.len
+        && (pscf->ssl_certificate->lengths
+            || pscf->ssl_certificate_key->lengths))
     {
         if (ngx_stream_proxy_ssl_certificate(s) != NGX_OK) {
             ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
@@ -1735,7 +1737,7 @@
 
                 cl->buf->temporary = (n ? 1 : 0);
                 cl->buf->last_buf = src->read->eof;
-                cl->buf->flush = 1;
+                cl->buf->flush = !src->read->eof;
 
                 (*packets)++;
                 *received += n;
@@ -2225,8 +2227,9 @@
         return NGX_ERROR;
     }
 
-    if (pscf->ssl_certificate) {
-
+    if (pscf->ssl_certificate
+        && pscf->ssl_certificate->value.len)
+    {
         if (pscf->ssl_certificate_key == NULL) {
             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
                           "no \"proxy_ssl_certificate_key\" is defined "
diff --git a/src/stream/ngx_stream_write_filter_module.c b/src/stream/ngx_stream_write_filter_module.c
index 156a61c..07dc7b5 100644
--- a/src/stream/ngx_stream_write_filter_module.c
+++ b/src/stream/ngx_stream_write_filter_module.c
@@ -235,7 +235,7 @@
     if (size == 0
         && !(c->buffered & NGX_LOWLEVEL_BUFFERED)
         && !(last && c->need_last_buf)
-        && !(c->type == SOCK_DGRAM && flush))
+        && !(flush && c->need_flush_buf))
     {
         if (last || flush || sync) {
             for (cl = *out; cl; /* void */) {