changeset 9021:8d0753760546 quic

Merged with the default branch.
author Sergey Kandaurov <pluknet@nginx.com>
date Wed, 22 Jun 2022 18:34:58 +0400
parents efbcdb9b37dc (current diff) fecd73db563f (diff)
children b30bec3d71d6
files README src/http/ngx_http.h src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h src/http/ngx_http_parse.c src/http/ngx_http_request.c src/http/ngx_http_request.h src/http/ngx_http_upstream.c src/http/v3/ngx_http_v3_filter_module.c src/stream/ngx_stream_proxy_module.c
diffstat 46 files changed, 1302 insertions(+), 1298 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags
+++ b/.hgtags
@@ -467,3 +467,4 @@ 2217a9c1d0b86026f22700b3c089545db1964f55
 39be8a682c58308d9399cddd57e37f9fdb7bdf3e release-1.21.4
 d986378168fd4d70e0121cabac274c560cca9bdf release-1.21.5
 714eb4b2c09e712fb2572a2164ce2bf67638ccac release-1.21.6
+5da2c0902e8e2aa4534008a582a60c61c135960e release-1.23.0
--- a/README
+++ b/README
@@ -15,7 +15,7 @@ 1. Introduction
 
     The code is developed in a separate "quic" branch available
     at https://hg.nginx.org/nginx-quic.  Currently it is based
-    on nginx mainline 1.21.x.  We merge new nginx releases into
+    on nginx mainline 1.23.x.  We merge new nginx releases into
     this branch regularly.
 
     The project code base is under the same BSD license as nginx.
--- a/auto/os/conf
+++ b/auto/os/conf
@@ -110,7 +110,7 @@ case "$NGX_MACHINE" in
         NGX_MACH_CACHE_LINE=64
     ;;
 
-    aarch64 )
+    aarch64 | arm64)
         have=NGX_ALIGNMENT value=16 . auto/define
         NGX_MACH_CACHE_LINE=64
     ;;
--- a/contrib/vim/syntax/nginx.vim
+++ b/contrib/vim/syntax/nginx.vim
@@ -111,19 +111,14 @@ syn keyword ngxDirectiveControl containe
 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_
 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_m
 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 ip_ha
 syn keyword ngxDirective contained js_access
 syn keyword ngxDirective contained js_body_filter
 syn keyword ngxDirective contained js_content
+syn keyword ngxDirective contained js_fetch_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 max_r
 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 statu
 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_
 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
-" -----------------------------------------------------------------------------
-
-" 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
+" 3rd party modules list taken from
+" https://github.com/freebsd/freebsd-ports/blob/main/www/nginx-devel/Makefile.extmod
+" ----------------------------------------------------------------------------------
 
-" 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
+" 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_buffer_size
 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 conta
 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 conta
 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 conta
 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 conta
 syn keyword ngxDirectiveThirdParty contained content_handler_type
 syn keyword ngxDirectiveThirdParty contained handler_code
 syn keyword ngxDirectiveThirdParty contained handler_name
+syn keyword ngxDirectiveThirdParty contained handler_type
 syn keyword ngxDirectiveThirdParty contained handlers_lazy_init
-syn keyword ngxDirectiveThirdParty contained handler_type
 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 conta
 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 conta
 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
+
+" 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
 
-" ngx_headers_more
+" 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 conta
 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 conta
 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 conta
 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_event_string
 syn keyword ngxDirectiveThirdParty contained nchan_channel_events_channel_id
-syn keyword ngxDirectiveThirdParty contained nchan_channel_event_string
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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 conta
 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
--- 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">
--- a/misc/GNUmakefile
+++ b/misc/GNUmakefile
@@ -6,8 +6,8 @@ TEMP =		tmp
 
 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 @@ release: export
 
 	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)
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -9,8 +9,8 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define nginx_version      1021007
-#define NGINX_VERSION      "1.21.7"
+#define nginx_version      1023000
+#define NGINX_VERSION      "1.23.0"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #ifdef NGX_BUILD
--- a/src/core/ngx_hash.h
+++ b/src/core/ngx_hash.h
@@ -89,12 +89,15 @@ typedef struct {
 } 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);
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -1389,6 +1389,7 @@ ngx_resolver_send_tcp_query(ngx_resolver
 
         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;
 
--- a/src/http/modules/ngx_http_auth_basic_module.c
+++ b/src/http/modules/ngx_http_auth_basic_module.c
@@ -339,6 +339,7 @@ ngx_http_auth_basic_set_realm(ngx_http_r
     *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;
--- a/src/http/modules/ngx_http_auth_request_module.c
+++ b/src/http/modules/ngx_http_auth_request_module.c
@@ -101,7 +101,7 @@ ngx_module_t  ngx_http_auth_request_modu
 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 @@ ngx_http_auth_request_handler(ngx_http_r
                 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;
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -1082,6 +1082,7 @@ ngx_http_dav_location(ngx_http_request_t
     }
 
     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);
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -835,14 +835,14 @@ static ngx_int_t
 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 @@ ngx_http_fastcgi_create_request(ngx_http
         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 @@ ngx_http_fastcgi_create_request(ngx_http
                 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 @@ ngx_http_fastcgi_create_request(ngx_http
                     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 @@ ngx_http_fastcgi_create_request(ngx_http
 
             for (n = 0; n < header_params; n++) {
                 if (&header[i] == ignored[n]) {
-                    goto next;
+                    goto next_value;
                 }
             }
 
@@ -1125,6 +1143,11 @@ ngx_http_fastcgi_create_request(ngx_http
             }
 
             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 @@ ngx_http_fastcgi_create_request(ngx_http
                 *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 @@ ngx_http_fastcgi_process_header(ngx_http
                 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,
--- a/src/http/modules/ngx_http_geo_module.c
+++ b/src/http/modules/ngx_http_geo_module.c
@@ -327,15 +327,15 @@ static ngx_int_t
 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);
     }
--- a/src/http/modules/ngx_http_geoip_module.c
+++ b/src/http/modules/ngx_http_geoip_module.c
@@ -240,16 +240,16 @@ static u_long
 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 @@ static geoipv6_t
 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 @@ ngx_http_geoip_addr_v6(ngx_http_request_
     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);
     }
--- a/src/http/modules/ngx_http_grpc_module.c
+++ b/src/http/modules/ngx_http_grpc_module.c
@@ -1891,8 +1891,12 @@ ngx_http_grpc_process_header(ngx_http_re
                 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 @@ ngx_http_grpc_set_ssl(ngx_conf_t *cf, ng
         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 "
--- a/src/http/modules/ngx_http_gzip_filter_module.c
+++ b/src/http/modules/ngx_http_gzip_filter_module.c
@@ -280,6 +280,7 @@ ngx_http_gzip_header_filter(ngx_http_req
     }
 
     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;
--- a/src/http/modules/ngx_http_gzip_static_module.c
+++ b/src/http/modules/ngx_http_gzip_static_module.c
@@ -242,6 +242,7 @@ ngx_http_gzip_static_handler(ngx_http_re
     }
 
     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;
--- a/src/http/modules/ngx_http_headers_filter_module.c
+++ b/src/http/modules/ngx_http_headers_filter_module.c
@@ -329,8 +329,7 @@ ngx_http_set_expires(ngx_http_request_t 
     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 @@ ngx_http_set_expires(ngx_http_request_t 
         }
 
         r->headers_out.expires = e;
+        e->next = NULL;
 
         e->hash = 1;
         ngx_str_set(&e->key, "Expires");
@@ -371,38 +371,29 @@ ngx_http_set_expires(ngx_http_request_t 
     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 (cc == NULL) {
 
-        if (ngx_array_init(&r->headers_out.cache_control, r->pool,
-                           1, sizeof(ngx_table_elt_t *))
-            != NGX_OK)
-        {
+        cc = ngx_list_push(&r->headers_out.headers);
+        if (cc == NULL) {
+            e->hash = 0;
             return NGX_ERROR;
         }
 
-        cc = ngx_list_push(&r->headers_out.headers);
-        if (cc == NULL) {
-            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;
+    } else {
+        for (cc = cc->next; cc; cc = cc->next) {
+            cc->hash = 0;
         }
 
-        *ccp = cc;
-
-    } else {
-        for (i = 1; i < r->headers_out.cache_control.nelts; i++) {
-            ccp[i]->hash = 0;
-        }
-
-        cc = ccp[0];
+        cc = r->headers_out.cache_control;
+        cc->next = NULL;
     }
 
     if (expires == NGX_HTTP_EXPIRES_EPOCH) {
@@ -420,6 +411,8 @@ ngx_http_set_expires(ngx_http_request_t 
 
     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 @@ ngx_http_set_expires(ngx_http_request_t 
     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 @@ static ngx_int_t
 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 @@ ngx_http_add_multi_header_lines(ngx_http
     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 @@ ngx_http_set_response_header(ngx_http_re
         }
 
         *old = h;
+        h->next = NULL;
     }
 
     h->hash = 1;
--- a/src/http/modules/ngx_http_memcached_module.c
+++ b/src/http/modules/ngx_http_memcached_module.c
@@ -401,6 +401,7 @@ found:
             }
 
             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;
--- a/src/http/modules/ngx_http_mp4_module.c
+++ b/src/http/modules/ngx_http_mp4_module.c
@@ -2331,7 +2331,7 @@ ngx_http_mp4_crop_stts_data(ngx_http_mp4
         }
 
         start_sample += count;
-        start_time -= count * duration;
+        start_time -= (uint64_t) count * duration;
         entries--;
         entry++;
     }
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -1930,8 +1930,12 @@ ngx_http_proxy_process_header(ngx_http_r
             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,
@@ -1965,6 +1969,7 @@ ngx_http_proxy_process_header(ngx_http_r
                 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) {
@@ -1978,6 +1983,7 @@ ngx_http_proxy_process_header(ngx_http_r
                 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 */
@@ -2559,22 +2565,20 @@ static ngx_int_t
 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) {
@@ -2593,8 +2597,8 @@ ngx_http_proxy_add_x_forwarded_for_varia
     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++ = ' ';
     }
 
@@ -4951,8 +4955,9 @@ ngx_http_proxy_set_ssl(ngx_conf_t *cf, n
         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 "
--- a/src/http/modules/ngx_http_range_filter_module.c
+++ b/src/http/modules/ngx_http_range_filter_module.c
@@ -258,6 +258,7 @@ next_filter:
     }
 
     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 @@ ngx_http_range_singlepart_header(ngx_htt
     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 @@ ngx_http_range_not_satisfiable(ngx_http_
     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,
--- a/src/http/modules/ngx_http_realip_module.c
+++ b/src/http/modules/ngx_http_realip_module.c
@@ -134,9 +134,8 @@ ngx_http_realip_handler(ngx_http_request
     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 @@ ngx_http_realip_handler(ngx_http_request
 
     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;
         }
 
--- a/src/http/modules/ngx_http_scgi_module.c
+++ b/src/http/modules/ngx_http_scgi_module.c
@@ -633,14 +633,14 @@ static ngx_int_t
 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 @@ ngx_http_scgi_create_request(ngx_http_re
         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 @@ ngx_http_scgi_create_request(ngx_http_re
                 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 @@ ngx_http_scgi_create_request(ngx_http_re
 
             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 @@ ngx_http_scgi_create_request(ngx_http_re
 
             for (n = 0; n < header_params; n++) {
                 if (&header[i] == ignored[n]) {
-                    goto next;
+                    goto next_value;
                 }
             }
 
@@ -893,12 +912,33 @@ ngx_http_scgi_create_request(ngx_http_re
 
             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 @@ ngx_http_scgi_process_header(ngx_http_re
             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,
--- a/src/http/modules/ngx_http_static_module.c
+++ b/src/http/modules/ngx_http_static_module.c
@@ -195,6 +195,7 @@ ngx_http_static_handler(ngx_http_request
         }
 
         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;
--- a/src/http/modules/ngx_http_userid_filter_module.c
+++ b/src/http/modules/ngx_http_userid_filter_module.c
@@ -319,10 +319,9 @@ ngx_http_userid_set_variable(ngx_http_re
 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_userid_get_uid(ngx_http_request
         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 @@ ngx_http_userid_get_uid(ngx_http_request
                    "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 @@ ngx_http_userid_get_uid(ngx_http_request
     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;
     }
 
--- a/src/http/modules/ngx_http_uwsgi_module.c
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -845,13 +845,13 @@ ngx_http_uwsgi_create_key(ngx_http_reque
 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 @@ ngx_http_uwsgi_create_request(ngx_http_r
         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 @@ ngx_http_uwsgi_create_request(ngx_http_r
                 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 @@ ngx_http_uwsgi_create_request(ngx_http_r
 
             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 @@ ngx_http_uwsgi_create_request(ngx_http_r
 
             for (n = 0; n < header_params; n++) {
                 if (&header[i] == ignored[n]) {
-                    goto next;
+                    goto next_value;
                 }
             }
 
@@ -1109,15 +1128,41 @@ ngx_http_uwsgi_create_request(ngx_http_r
             }
 
             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 @@ ngx_http_uwsgi_process_header(ngx_http_r
             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 @@ ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, n
         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 "
--- a/src/http/modules/perl/nginx.xs
+++ b/src/http/modules/perl/nginx.xs
@@ -269,10 +269,9 @@ header_in(r, key)
     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 @@ header_in(r, key)
 
     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;
+
+        } else {
+            sep = ',';
         }
-#if (NGX_HTTP_X_FORWARDED_FOR)
-        if (hh->offset == offsetof(ngx_http_headers_in_t, x_forwarded_for)) {
-            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 @@ header_in(r, key)
             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_out(r, key, value)
     }
 
     header->hash = 1;
+    header->next = NULL;
 
     if (ngx_http_perl_sv2str(aTHX_ r, &header->key, key) != NGX_OK) {
         header->hash = 0;
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -108,10 +108,10 @@ ngx_int_t ngx_http_parse_unsafe_uri(ngx_
     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,
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -1007,6 +1007,7 @@ ngx_http_core_find_config_phase(ngx_http
         }
 
         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_int_t
 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 @@ ngx_http_core_access_phase(ngx_http_requ
         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 @@ ngx_http_set_etag(ngx_http_request_t *r)
     }
 
     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 @@ ngx_http_send_response(ngx_http_request_
         }
 
         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 @@ ngx_http_gzip_ok(ngx_http_request_t *r)
 {
     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 @@ ngx_http_gzip_ok(ngx_http_request_t *r)
         return NGX_DECLINED;
     }
 
-    cc = &r->headers_out.cache_control;
-
-    if (cc->elts) {
+    cc = r->headers_out.cache_control;
+
+    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_http_set_disable_symlinks(ngx_http_r
 
 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 @@ ngx_http_get_forwarded_addr(ngx_http_req
                                                     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 @@ ngx_http_get_forwarded_addr(ngx_http_req
         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_http_get_forwarded_addr_internal(ngx
 }
 
 
+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)
 {
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -533,9 +533,11 @@ ngx_int_t ngx_http_set_disable_symlinks(
     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;
 
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -1960,27 +1960,24 @@ unsafe:
 }
 
 
-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;
-
-    h = headers->elts;
-
-    for (i = 0; i < headers->nelts; i++) {
-
-        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) {
+    u_char           *start, *last, *end, ch;
+    ngx_table_elt_t  *h;
+
+    for (h = headers; h; h = h->next) {
+
+        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "parse header: \"%V: %V\"", &h->key, &h->value);
+
+        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 @@ ngx_http_parse_multi_header_lines(ngx_ar
 
             if (value == NULL) {
                 if (start == end || *start == ',') {
-                    return i;
+                    return h;
                 }
 
                 goto skip;
@@ -2014,7 +2011,7 @@ ngx_http_parse_multi_header_lines(ngx_ar
             value->len = last - start;
             value->data = start;
 
-            return i;
+            return h;
 
         skip:
 
@@ -2029,31 +2026,28 @@ ngx_http_parse_multi_header_lines(ngx_ar
         }
     }
 
-    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;
-
-    h = headers->elts;
-
-    for (i = 0; i < headers->nelts; i++) {
-
-        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) {
+    u_char           *start, *last, *end;
+    ngx_table_elt_t  *h;
+
+    for (h = headers; h; h = h->next) {
+
+        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "parse header: \"%V: %V\"", &h->key, &h->value);
+
+        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 @@ ngx_http_parse_set_cookie_lines(ngx_arra
         value->len = last - start;
         value->data = start;
 
-        return i;
+        return h;
     }
 
-    return NGX_DECLINED;
+    return NULL;
 }
 
 
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -22,8 +22,6 @@ static ngx_int_t ngx_http_process_header
     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,
@@ -159,7 +157,7 @@ ngx_http_header_t  ngx_http_headers_in[]
 #if (NGX_HTTP_X_FORWARDED_FOR)
     { 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)
@@ -191,8 +189,8 @@ ngx_http_header_t  ngx_http_headers_in[]
                  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 }
 };
@@ -1752,9 +1750,10 @@ ngx_http_process_header_line(ngx_http_re
 
     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;
 }
@@ -1770,6 +1769,7 @@ ngx_http_process_unique_header_line(ngx_
 
     if (*ph == NULL) {
         *ph = h;
+        h->next = NULL;
         return NGX_OK;
     }
 
@@ -1802,6 +1802,7 @@ ngx_http_process_host(ngx_http_request_t
     }
 
     r->headers_in.host = h;
+    h->next = NULL;
 
     host = h->value;
 
@@ -1837,6 +1838,10 @@ static ngx_int_t
 ngx_http_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h,
     ngx_uint_t offset)
 {
+    if (ngx_http_process_header_line(r, h, offset) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
     if (ngx_strcasestrn(h->value.data, "close", 5 - 1)) {
         r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE;
 
@@ -1854,12 +1859,10 @@ ngx_http_process_user_agent(ngx_http_req
 {
     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;
@@ -1921,35 +1924,6 @@ ngx_http_process_user_agent(ngx_http_req
 }
 
 
-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)
 {
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -213,7 +213,7 @@ typedef struct {
     ngx_table_elt_t                  *keep_alive;
 
 #if (NGX_HTTP_X_FORWARDED_FOR)
-    ngx_array_t                       x_forwarded_for;
+    ngx_table_elt_t                  *x_forwarded_for;
 #endif
 
 #if (NGX_HTTP_REALIP)
@@ -232,17 +232,19 @@ typedef struct {
     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;
@@ -273,6 +275,9 @@ typedef struct {
     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;
@@ -281,9 +286,6 @@ typedef struct {
     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;
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -1243,6 +1243,7 @@ ngx_http_script_regex_end_code(ngx_http_
         }
 
         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;
 
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -649,6 +649,7 @@ ngx_http_send_error_page(ngx_http_reques
     }
 
     location->hash = 1;
+    location->next = NULL;
     ngx_str_set(&location->key, "Location");
     location->value = uri;
 
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -101,6 +101,9 @@ static void ngx_http_upstream_finalize_r
 
 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_rewri
 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)
-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 @@ static ngx_http_upstream_header_t  ngx_h
                  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 @@ static ngx_http_upstream_header_t  ngx_h
                  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 @@ static ngx_http_upstream_header_t  ngx_h
                  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 @@ static ngx_http_upstream_header_t  ngx_h
                  ngx_http_upstream_process_transfer_encoding, 0,
                  ngx_http_upstream_ignore_header_line, 0, 0 },
 
-#if (NGX_HTTP_GZIP)
     { 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 }
 };
@@ -1714,8 +1710,10 @@ ngx_http_upstream_ssl_init_connection(ng
         }
     }
 
-    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,
@@ -2671,7 +2669,7 @@ ngx_http_upstream_intercept_errors(ngx_h
 {
     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;
 
@@ -2700,23 +2698,36 @@ ngx_http_upstream_intercept_errors(ngx_h
             if (status == NGX_HTTP_UNAUTHORIZED
                 && u->headers_in.www_authenticate)
             {
-                h = ngx_list_push(&r->headers_out.headers);
-
-                if (h == NULL) {
-                    ngx_http_upstream_finalize_request(r, u,
+                h = u->headers_in.www_authenticate;
+                ph = &r->headers_out.www_authenticate;
+
+                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;
 
@@ -2811,6 +2822,10 @@ ngx_http_upstream_process_headers(ngx_ht
 
     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))
     {
@@ -2831,6 +2846,10 @@ ngx_http_upstream_process_headers(ngx_ht
                 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);
 
@@ -2884,6 +2903,10 @@ ngx_http_upstream_process_headers(ngx_ht
             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))
         {
@@ -4635,9 +4658,35 @@ ngx_http_upstream_process_header_line(ng
 
     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;
 }
@@ -4659,9 +4708,34 @@ ngx_http_upstream_process_content_length
 
     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;
 }
 
@@ -4674,6 +4748,18 @@ ngx_http_upstream_process_last_modified(
 
     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);
@@ -4686,26 +4772,16 @@ static ngx_int_t
 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;
-
-    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;
-    }
+    ph = &u->headers_in.set_cookie;
+
+    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)) {
@@ -4721,26 +4797,16 @@ static ngx_int_t
 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;
-
-    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;
-    }
+    ph = &u->headers_in.cache_control;
+
+    while (*ph) { ph = &(*ph)->next; }
 
     *ph = h;
+    h->next = NULL;
 
 #if (NGX_HTTP_CACHE)
     {
@@ -4755,18 +4821,18 @@ ngx_http_upstream_process_cache_control(
         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;
     }
 
@@ -4796,12 +4862,15 @@ ngx_http_upstream_process_cache_control(
         }
 
         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);
@@ -4862,7 +4931,20 @@ ngx_http_upstream_process_expires(ngx_ht
     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)
     {
@@ -4883,7 +4965,7 @@ ngx_http_upstream_process_expires(ngx_ht
     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;
     }
 
@@ -4902,7 +4984,20 @@ ngx_http_upstream_process_accel_expires(
     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)
     {
@@ -4934,6 +5029,8 @@ ngx_http_upstream_process_accel_expires(
 
         default:
             r->cache->valid_sec = ngx_time() + n;
+            u->headers_in.no_cache = 0;
+            u->headers_in.expired = 0;
             return NGX_OK;
         }
     }
@@ -4945,6 +5042,8 @@ ngx_http_upstream_process_accel_expires(
 
     if (n != NGX_ERROR) {
         r->cache->valid_sec = n;
+        u->headers_in.no_cache = 0;
+        u->headers_in.expired = 0;
     }
     }
 #endif
@@ -4961,7 +5060,20 @@ ngx_http_upstream_process_limit_rate(ngx
     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;
@@ -5020,7 +5132,11 @@ static ngx_int_t
 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;
     }
 
@@ -5034,13 +5150,22 @@ static ngx_int_t
 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;
@@ -5051,13 +5176,40 @@ static ngx_int_t
 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;
-
-    if (ngx_strlcasestrn(h->value.data, h->value.data + h->value.len,
-                         (u_char *) "chunked", 7 - 1)
-        != NULL)
+    ngx_http_upstream_t  *u;
+
+    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;
@@ -5068,29 +5220,74 @@ static ngx_int_t
 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 == 1 && h->value.data[0] == '*') {
+        u->cacheable = 0;
         return NGX_OK;
     }
 
-    if (h->value.len > NGX_HTTP_CACHE_VARY_LEN
-        || (h->value.len == 1 && h->value.data[0] == '*'))
-    {
+    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;
@@ -5113,6 +5310,7 @@ ngx_http_upstream_copy_header_line(ngx_h
     if (offset) {
         ph = (ngx_table_elt_t **) ((char *) &r->headers_out + offset);
         *ph = ho;
+        ho->next = NULL;
     }
 
     return NGX_OK;
@@ -5123,18 +5321,8 @@ static ngx_int_t
 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;
@@ -5142,12 +5330,12 @@ ngx_http_upstream_copy_multi_header_line
 
     *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;
 }
@@ -5217,6 +5405,7 @@ ngx_http_upstream_copy_last_modified(ngx
     }
 
     *ho = *h;
+    ho->next = NULL;
 
     r->headers_out.last_modified = ho;
     r->headers_out.last_modified_time =
@@ -5239,6 +5428,7 @@ ngx_http_upstream_rewrite_location(ngx_h
     }
 
     *ho = *h;
+    ho->next = NULL;
 
     if (r->upstream->rewrite_redirect) {
         rc = r->upstream->rewrite_redirect(r, ho, 0);
@@ -5284,6 +5474,7 @@ ngx_http_upstream_rewrite_refresh(ngx_ht
     }
 
     *ho = *h;
+    ho->next = NULL;
 
     if (r->upstream->rewrite_redirect) {
 
@@ -5329,6 +5520,7 @@ ngx_http_upstream_rewrite_set_cookie(ngx
     }
 
     *ho = *h;
+    ho->next = NULL;
 
     if (r->upstream->rewrite_cookie) {
         rc = r->upstream->rewrite_cookie(r, ho);
@@ -5382,6 +5574,7 @@ ngx_http_upstream_copy_allow_ranges(ngx_
     }
 
     *ho = *h;
+    ho->next = NULL;
 
     r->headers_out.accept_ranges = ho;
 
@@ -5389,29 +5582,6 @@ ngx_http_upstream_copy_allow_ranges(ngx_
 }
 
 
-#if (NGX_HTTP_GZIP)
-
-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)
 {
@@ -5723,7 +5893,7 @@ ngx_http_upstream_header_variable(ngx_ht
         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);
 }
@@ -5738,7 +5908,7 @@ ngx_http_upstream_trailer_variable(ngx_h
         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);
 }
@@ -5760,9 +5930,9 @@ ngx_http_upstream_cookie_variable(ngx_ht
     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;
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -280,23 +280,21 @@ typedef struct {
 
     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_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;
 
 
--- 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_heade
 
 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 @@ static ngx_http_variable_t  ngx_http_cor
 #endif
 
 #if (NGX_HTTP_X_FORWARDED_FOR)
-    { 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 @@ static ngx_http_variable_t  ngx_http_cor
     { 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 @@ static ngx_int_t
 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 @@ ngx_http_variable_cookies(ngx_http_reque
 
 
 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;
-
-    a = (ngx_array_t *) ((char *) r + data);
-
-    n = a->nelts;
-    h = a->elts;
+    size_t            len;
+    u_char           *p;
+    ngx_table_elt_t  *h, *th;
+
+    h = *(ngx_table_elt_t **) ((char *) r + data);
 
     len = 0;
 
-    for (i = 0; i < n; i++) {
-
-        if (h[i]->hash == 0) {
+    for (th = h; th; th = th->next) {
+
+        if (th->hash == 0) {
             continue;
         }
 
-        len += h[i]->value.len + 2;
+        len += th->value.len + 2;
     }
 
     if (len == 0) {
@@ -879,9 +849,9 @@ ngx_http_variable_headers_internal(ngx_h
     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 @@ ngx_http_variable_headers_internal(ngx_h
     v->len = len;
     v->data = p;
 
-    end = p + len;
-
-    for (i = 0; /* void */ ; i++) {
-
-        if (h[i]->hash == 0) {
+    for (th = h; th; th = th->next) {
+
+        if (th->hash == 0) {
             continue;
         }
 
-        p = ngx_copy(p, h[i]->value.data, h[i]->value.len);
-
-        if (p == end) {
+        p = ngx_copy(p, th->value.data, th->value.len);
+
+        if (th->next == NULL) {
             break;
         }
 
@@ -919,7 +887,7 @@ static ngx_int_t
 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 @@ static ngx_int_t
 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 @@ static ngx_int_t
 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 @@ ngx_http_variable_unknown_header(ngx_htt
             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 @@ ngx_http_variable_unknown_header(ngx_htt
             }
         }
 
-        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 @@ ngx_http_variable_cookie(ngx_http_reques
     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_http_variable_sent_location(ngx_http
 
     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);
 }
--- 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_
 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)
--- a/src/http/v2/ngx_http_v2_filter_module.c
+++ b/src/http/v2/ngx_http_v2_filter_module.c
@@ -674,14 +674,14 @@ ngx_http_v2_header_filter(ngx_http_reque
 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");
@@ -725,15 +725,13 @@ ngx_http_v2_push_resources(ngx_http_requ
         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);
-
-        start = h[i]->value.data;
-        end = h[i]->value.data + h[i]->value.len;
+                       "http2 parse link: \"%V\"", &h->value);
+
+        start = h->value.data;
+        end = h->value.data + h->value.len;
 
     next_link:
 
--- a/src/http/v3/ngx_http_v3_filter_module.c
+++ b/src/http/v3/ngx_http_v3_filter_module.c
@@ -609,13 +609,13 @@ ngx_http_v3_header_filter(ngx_http_reque
 static ngx_int_t
 ngx_http_v3_push_resources(ngx_http_request_t *r, ngx_chain_t ***out)
 {
-    u_char                     *start, *end, *last;
-    ngx_str_t                   path;
-    ngx_int_t                   rc;
-    ngx_uint_t                  i, push;
-    ngx_table_elt_t           **h;
-    ngx_http_v3_loc_conf_t     *h3lcf;
-    ngx_http_complex_value_t   *pushes;
+    u_char                    *start, *end, *last;
+    ngx_str_t                  path;
+    ngx_int_t                  rc;
+    ngx_uint_t                 i, push;
+    ngx_table_elt_t           *h;
+    ngx_http_v3_loc_conf_t    *h3lcf;
+    ngx_http_complex_value_t  *pushes;
 
     h3lcf = ngx_http_get_module_loc_conf(r, ngx_http_v3_module);
 
@@ -654,15 +654,13 @@ ngx_http_v3_push_resources(ngx_http_requ
         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,
-                       "http3 parse link: \"%V\"", &h[i]->value);
+                       "http3 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:
 
--- a/src/os/unix/ngx_readv_chain.c
+++ b/src/os/unix/ngx_readv_chain.c
@@ -55,7 +55,9 @@ ngx_readv_chain(ngx_connection_t *c, ngx
 
 #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);
--- a/src/os/unix/ngx_recv.c
+++ b/src/os/unix/ngx_recv.c
@@ -52,7 +52,9 @@ ngx_unix_recv(ngx_connection_t *c, u_cha
 
 #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);
--- a/src/stream/ngx_stream_proxy_module.c
+++ b/src/stream/ngx_stream_proxy_module.c
@@ -1069,8 +1069,10 @@ ngx_stream_proxy_ssl_init_connection(ngx
         }
     }
 
-    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 @@ ngx_stream_proxy_process(ngx_stream_sess
 
                 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;
@@ -2240,8 +2242,9 @@ ngx_stream_proxy_set_ssl(ngx_conf_t *cf,
         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 "