summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrobert <robert@openbsd.org>2014-06-12 15:27:08 +0000
committerrobert <robert@openbsd.org>2014-06-12 15:27:08 +0000
commit48c5ce6cae7e303dfeee3a51091514ba4307bd3d (patch)
tree2c947b91869e053e1c22daedc8be6fc26be784d6
parentDisable the "switch to insertion sort" optimization to avoid quadratic (diff)
downloadwireguard-openbsd-48c5ce6cae7e303dfeee3a51091514ba4307bd3d.tar.xz
wireguard-openbsd-48c5ce6cae7e303dfeee3a51091514ba4307bd3d.zip
update to 1.6.0 with official syslog support backported from the 1.7 branch
tested by several, ok sthen@
-rw-r--r--usr.sbin/nginx/CHANGES305
-rw-r--r--usr.sbin/nginx/CHANGES.ru318
-rw-r--r--usr.sbin/nginx/Makefile.bsd-wrapper3
-rw-r--r--usr.sbin/nginx/auto/cc/clang7
-rw-r--r--usr.sbin/nginx/auto/cc/conf23
-rw-r--r--usr.sbin/nginx/auto/cc/msvc1
-rw-r--r--usr.sbin/nginx/auto/cc/name2
-rw-r--r--usr.sbin/nginx/auto/cc/owc8
-rw-r--r--usr.sbin/nginx/auto/cc/sunc2
-rw-r--r--usr.sbin/nginx/auto/endianness4
-rw-r--r--usr.sbin/nginx/auto/feature2
-rw-r--r--usr.sbin/nginx/auto/include2
-rw-r--r--usr.sbin/nginx/auto/lib/libatomic/make4
-rw-r--r--usr.sbin/nginx/auto/lib/openssl/conf4
-rw-r--r--usr.sbin/nginx/auto/lib/openssl/make2
-rw-r--r--usr.sbin/nginx/auto/lib/pcre/conf5
-rw-r--r--usr.sbin/nginx/auto/lib/pcre/make22
-rw-r--r--usr.sbin/nginx/auto/lib/pcre/makefile.bcc7
-rw-r--r--usr.sbin/nginx/auto/lib/pcre/makefile.msvc3
-rw-r--r--usr.sbin/nginx/auto/lib/pcre/makefile.owc3
-rw-r--r--usr.sbin/nginx/auto/lib/perl/make1
-rw-r--r--usr.sbin/nginx/auto/lib/test2
-rw-r--r--usr.sbin/nginx/auto/lib/zlib/make23
-rw-r--r--usr.sbin/nginx/auto/modules8
-rw-r--r--usr.sbin/nginx/auto/options3
-rw-r--r--usr.sbin/nginx/auto/os/darwin2
-rw-r--r--usr.sbin/nginx/auto/os/linux32
-rw-r--r--usr.sbin/nginx/auto/os/win3213
-rw-r--r--usr.sbin/nginx/auto/sources12
-rw-r--r--usr.sbin/nginx/auto/types/sizeof2
-rw-r--r--usr.sbin/nginx/auto/types/typedef2
-rw-r--r--usr.sbin/nginx/auto/types/uintptr_t2
-rwxr-xr-xusr.sbin/nginx/auto/unix14
-rw-r--r--usr.sbin/nginx/conf/mime.types9
-rw-r--r--usr.sbin/nginx/conf/nginx.conf8
-rw-r--r--usr.sbin/nginx/contrib/README6
-rw-r--r--usr.sbin/nginx/src/core/nginx.c9
-rw-r--r--usr.sbin/nginx/src/core/nginx.h4
-rw-r--r--usr.sbin/nginx/src/core/ngx_conf_file.c96
-rw-r--r--usr.sbin/nginx/src/core/ngx_conf_file.h6
-rw-r--r--usr.sbin/nginx/src/core/ngx_config.h4
-rw-r--r--usr.sbin/nginx/src/core/ngx_connection.c129
-rw-r--r--usr.sbin/nginx/src/core/ngx_connection.h11
-rw-r--r--usr.sbin/nginx/src/core/ngx_core.h2
-rw-r--r--usr.sbin/nginx/src/core/ngx_cycle.c128
-rw-r--r--usr.sbin/nginx/src/core/ngx_cycle.h2
-rw-r--r--usr.sbin/nginx/src/core/ngx_file.c108
-rw-r--r--usr.sbin/nginx/src/core/ngx_file.h3
-rw-r--r--usr.sbin/nginx/src/core/ngx_hash.c15
-rw-r--r--usr.sbin/nginx/src/core/ngx_inet.c98
-rw-r--r--usr.sbin/nginx/src/core/ngx_inet.h6
-rw-r--r--usr.sbin/nginx/src/core/ngx_list.c10
-rw-r--r--usr.sbin/nginx/src/core/ngx_log.c385
-rw-r--r--usr.sbin/nginx/src/core/ngx_log.h29
-rw-r--r--usr.sbin/nginx/src/core/ngx_open_file_cache.c68
-rw-r--r--usr.sbin/nginx/src/core/ngx_palloc.c7
-rw-r--r--usr.sbin/nginx/src/core/ngx_proxy_protocol.c91
-rw-r--r--usr.sbin/nginx/src/core/ngx_proxy_protocol.h23
-rw-r--r--usr.sbin/nginx/src/core/ngx_resolver.c1335
-rw-r--r--usr.sbin/nginx/src/core/ngx_resolver.h36
-rw-r--r--usr.sbin/nginx/src/core/ngx_slab.c9
-rw-r--r--usr.sbin/nginx/src/core/ngx_slab.h2
-rw-r--r--usr.sbin/nginx/src/core/ngx_string.c91
-rw-r--r--usr.sbin/nginx/src/core/ngx_string.h2
-rw-r--r--usr.sbin/nginx/src/core/ngx_syslog.c342
-rw-r--r--usr.sbin/nginx/src/core/ngx_syslog.h30
-rw-r--r--usr.sbin/nginx/src/core/ngx_times.c21
-rw-r--r--usr.sbin/nginx/src/core/ngx_times.h1
-rw-r--r--usr.sbin/nginx/src/event/modules/ngx_devpoll_module.c4
-rw-r--r--usr.sbin/nginx/src/event/modules/ngx_epoll_module.c18
-rw-r--r--usr.sbin/nginx/src/event/modules/ngx_select_module.c2
-rw-r--r--usr.sbin/nginx/src/event/modules/ngx_win32_select_module.c4
-rw-r--r--usr.sbin/nginx/src/event/ngx_event.c1
-rw-r--r--usr.sbin/nginx/src/event/ngx_event.h13
-rw-r--r--usr.sbin/nginx/src/event/ngx_event_accept.c10
-rw-r--r--usr.sbin/nginx/src/event/ngx_event_connect.c4
-rw-r--r--usr.sbin/nginx/src/event/ngx_event_openssl.c317
-rw-r--r--usr.sbin/nginx/src/event/ngx_event_openssl.h21
-rw-r--r--usr.sbin/nginx/src/event/ngx_event_openssl_stapling.c58
-rw-r--r--usr.sbin/nginx/src/event/ngx_event_pipe.c45
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_access_module.c150
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_auth_basic_module.c2
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_auth_request_module.c444
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_autoindex_module.c3
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_charset_filter_module.c2
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_dav_module.c4
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_fastcgi_module.c287
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_gunzip_filter_module.c14
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_gzip_filter_module.c8
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_gzip_static_module.c2
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_headers_filter_module.c4
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_image_filter_module.c10
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_limit_req_module.c6
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_log_module.c176
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_map_module.c6
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_memcached_module.c31
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_mp4_module.c866
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_proxy_module.c153
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_range_filter_module.c19
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_realip_module.c21
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_referer_module.c206
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_scgi_module.c30
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_ssi_filter_module.c42
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_ssl_module.c124
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_ssl_module.h5
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_stub_status_module.c3
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_sub_filter_module.c214
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_upstream_ip_hash_module.c48
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_upstream_keepalive_module.c7
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_uwsgi_module.c234
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_xslt_filter_module.c38
-rw-r--r--usr.sbin/nginx/src/http/modules/perl/nginx.xs11
-rw-r--r--usr.sbin/nginx/src/http/modules/perl/ngx_http_perl_module.c4
-rw-r--r--usr.sbin/nginx/src/http/ngx_http.c24
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_cache.h6
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_copy_filter_module.c6
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_core_module.c166
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_core_module.h5
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_file_cache.c118
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_header_filter_module.c15
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_parse.c98
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_postpone_filter_module.c6
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_request.c133
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_request.h8
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_request_body.c14
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_script.c11
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_spdy.c1160
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_spdy.h79
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_spdy_filter_module.c549
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_spdy_module.c73
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_spdy_module.h5
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_special_response.c2
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_upstream.c404
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_upstream.h14
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_upstream_round_robin.c56
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_variables.c46
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_write_filter_module.c17
-rw-r--r--usr.sbin/nginx/src/mail/ngx_mail.c6
-rw-r--r--usr.sbin/nginx/src/mail/ngx_mail.h2
-rw-r--r--usr.sbin/nginx/src/mail/ngx_mail_auth_http_module.c1
-rw-r--r--usr.sbin/nginx/src/mail/ngx_mail_core_module.c3
-rw-r--r--usr.sbin/nginx/src/mail/ngx_mail_handler.c21
-rw-r--r--usr.sbin/nginx/src/mail/ngx_mail_parse.c34
-rw-r--r--usr.sbin/nginx/src/mail/ngx_mail_proxy_module.c61
-rw-r--r--usr.sbin/nginx/src/mail/ngx_mail_smtp_handler.c128
-rw-r--r--usr.sbin/nginx/src/mail/ngx_mail_ssl_module.c59
-rw-r--r--usr.sbin/nginx/src/mail/ngx_mail_ssl_module.h3
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_channel.c4
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_darwin_config.h1
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_darwin_init.c2
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_darwin_sendfile_chain.c30
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_errno.h3
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_files.h26
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_freebsd_config.h6
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_freebsd_init.c2
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_freebsd_rfork_thread.c2
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_freebsd_rfork_thread.h4
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_freebsd_sendfile_chain.c36
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_linux_config.h10
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_linux_sendfile_chain.c42
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_posix_config.h1
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_process.c5
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_process_cycle.c29
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_readv_chain.c3
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_recv.c5
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_solaris_config.h1
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_solaris_sendfilev_chain.c30
167 files changed, 8479 insertions, 2736 deletions
diff --git a/usr.sbin/nginx/CHANGES b/usr.sbin/nginx/CHANGES
index 4d9e62aa65b..1b502bf91c4 100644
--- a/usr.sbin/nginx/CHANGES
+++ b/usr.sbin/nginx/CHANGES
@@ -1,5 +1,37 @@
-Changes with nginx 1.4.7 18 Mar 2014
+Changes with nginx 1.6.0 24 Apr 2014
+
+ *) 1.6.x stable branch.
+
+
+Changes with nginx 1.5.13 08 Apr 2014
+
+ *) Change: improved hash table handling; the default values of the
+ "variables_hash_max_size" and "types_hash_bucket_size" were changed
+ to 1024 and 64 respectively.
+
+ *) Feature: the ngx_http_mp4_module now supports the "end" argument.
+
+ *) Feature: byte ranges support in the ngx_http_mp4_module and while
+ saving responses to cache.
+
+ *) Bugfix: alerts "ngx_slab_alloc() failed: no memory" no longer logged
+ when using shared memory in the "ssl_session_cache" directive and in
+ the ngx_http_limit_req_module.
+
+ *) Bugfix: the "underscores_in_headers" directive did not allow
+ underscore as a first character of a header.
+ Thanks to Piotr Sikora.
+
+ *) Bugfix: cache manager might hog CPU on exit in nginx/Windows.
+
+ *) Bugfix: nginx/Windows terminated abnormally if the
+ "ssl_session_cache" directive was used with the "shared" parameter.
+
+ *) Bugfix: in the ngx_http_spdy_module.
+
+
+Changes with nginx 1.5.12 18 Mar 2014
*) Security: a heap memory buffer overflow might occur in a worker
process while handling a specially crafted request by
@@ -8,11 +40,23 @@ Changes with nginx 1.4.7 18 Mar 2014
Thanks to Lucas Molas, researcher at Programa STIC, Fundación Dr.
Manuel Sadosky, Buenos Aires, Argentina.
+ *) Feature: the "proxy_protocol" parameters of the "listen" and
+ "real_ip_header" directives, the $proxy_protocol_addr variable.
+
*) Bugfix: in the "fastcgi_next_upstream" directive.
Thanks to Lucas Molas.
-Changes with nginx 1.4.6 04 Mar 2014
+Changes with nginx 1.5.11 04 Mar 2014
+
+ *) Security: memory corruption might occur in a worker process on 32-bit
+ platforms while handling a specially crafted request by
+ ngx_http_spdy_module, potentially resulting in arbitrary code
+ execution (CVE-2014-0088); the bug had appeared in 1.5.10.
+ Thanks to Lucas Molas, researcher at Programa STIC, Fundación Dr.
+ Manuel Sadosky, Buenos Aires, Argentina.
+
+ *) Feature: the $ssl_session_reused variable.
*) Bugfix: the "client_max_body_size" directive might not work when
reading a request body using chunked transfer encoding; the bug had
@@ -22,15 +66,71 @@ Changes with nginx 1.4.6 04 Mar 2014
*) Bugfix: a segmentation fault might occur in a worker process when
proxying WebSocket connections.
+ *) Bugfix: a segmentation fault might occur in a worker process if the
+ ngx_http_spdy_module was used on 32-bit platforms; the bug had
+ appeared in 1.5.10.
+
+ *) Bugfix: the $upstream_status variable might contain wrong data if the
+ "proxy_cache_use_stale" or "proxy_cache_revalidate" directives were
+ used.
+ Thanks to Piotr Sikora.
+
+ *) Bugfix: a segmentation fault might occur in a worker process if
+ errors with code 400 were redirected to a named location using the
+ "error_page" directive.
+
+ *) Bugfix: nginx/Windows could not be built with Visual Studio 2013.
+
+
+Changes with nginx 1.5.10 04 Feb 2014
+
+ *) Feature: the ngx_http_spdy_module now uses SPDY 3.1 protocol.
+ Thanks to Automattic and MaxCDN for sponsoring this work.
+
+ *) Feature: the ngx_http_mp4_module now skips tracks too short for a
+ seek requested.
+
+ *) Bugfix: a segmentation fault might occur in a worker process if the
+ $ssl_session_id variable was used in logs; the bug had appeared in
+ 1.5.9.
+
+ *) Bugfix: the $date_local and $date_gmt variables used wrong format
+ outside of the ngx_http_ssi_filter_module.
+
+ *) Bugfix: client connections might be immediately closed if deferred
+ accept was used; the bug had appeared in 1.3.15.
+
+ *) Bugfix: alerts "getsockopt(TCP_FASTOPEN) ... failed" appeared in logs
+ during binary upgrade on Linux; the bug had appeared in 1.5.8.
+ Thanks to Piotr Sikora.
+
+
+Changes with nginx 1.5.9 22 Jan 2014
+
+ *) Change: now nginx expects escaped URIs in "X-Accel-Redirect" headers.
+
+ *) Feature: the "ssl_buffer_size" directive.
+
+ *) Feature: the "limit_rate" directive can now be used to rate limit
+ responses sent in SPDY connections.
-Changes with nginx 1.4.5 11 Feb 2014
+ *) Feature: the "spdy_chunk_size" directive.
+
+ *) Feature: the "ssl_session_tickets" directive.
+ Thanks to Dirkjan Bussink.
*) Bugfix: the $ssl_session_id variable contained full session
serialized instead of just a session id.
Thanks to Ivan Ristić.
- *) Bugfix: client connections might be immediately closed if deferred
- accept was used; the bug had appeared in 1.3.15.
+ *) Bugfix: nginx incorrectly handled escaped "?" character in the
+ "include" SSI command.
+
+ *) Bugfix: the ngx_http_dav_module did not unescape destination URI of
+ the COPY and MOVE methods.
+
+ *) Bugfix: resolver did not understand domain names with a trailing dot.
+ Thanks to Yichun Zhang.
*) Bugfix: alerts "zero size buf in output" might appear in logs while
proxying; the bug had appeared in 1.3.9.
@@ -41,53 +141,217 @@ Changes with nginx 1.4.5 11 Feb 2014
*) Bugfix: proxied WebSocket connections might hang right after
handshake if the select, poll, or /dev/poll methods were used.
+ *) Bugfix: the "xclient" directive of the mail proxy module incorrectly
+ handled IPv6 client addresses.
+
+
+Changes with nginx 1.5.8 17 Dec 2013
+
+ *) Feature: IPv6 support in resolver.
+
+ *) Feature: the "listen" directive supports the "fastopen" parameter.
+ Thanks to Mathew Rodley.
+
+ *) Feature: SSL support in the ngx_http_uwsgi_module.
+ Thanks to Roberto De Ioris.
+
+ *) Feature: vim syntax highlighting scripts were added to contrib.
+ Thanks to Evan Miller.
+
*) Bugfix: a timeout might occur while reading client request body in an
SSL connection using chunked transfer encoding.
- *) Bugfix: memory leak in nginx/Windows.
+ *) Bugfix: the "master_process" directive did not work correctly in
+ nginx/Windows.
+
+ *) Bugfix: the "setfib" parameter of the "listen" directive might not
+ work.
+
+ *) Bugfix: in the ngx_http_spdy_module.
-Changes with nginx 1.4.4 19 Nov 2013
+Changes with nginx 1.5.7 19 Nov 2013
*) Security: a character following an unescaped space in a request line
was handled incorrectly (CVE-2013-4547); the bug had appeared in
0.8.41.
Thanks to Ivan Fratric of the Google Security Team.
+ *) Change: a logging level of auth_basic errors about no user/password
+ provided has been lowered from "error" to "info".
-Changes with nginx 1.4.3 08 Oct 2013
+ *) Feature: the "proxy_cache_revalidate", "fastcgi_cache_revalidate",
+ "scgi_cache_revalidate", and "uwsgi_cache_revalidate" directives.
- *) Bugfix: a segmentation fault might occur in a worker process if the
- ngx_http_spdy_module was used with the "client_body_in_file_only"
- directive.
+ *) Feature: the "ssl_session_ticket_key" directive.
+ Thanks to Piotr Sikora.
- *) Bugfix: a segmentation fault might occur on start or during
- reconfiguration if the "try_files" directive was used with an empty
- parameter.
+ *) Bugfix: the directive "add_header Cache-Control ''" added a
+ "Cache-Control" response header line with an empty value.
- *) Bugfix: the $request_time variable did not work in nginx/Windows.
+ *) Bugfix: the "satisfy any" directive might return 403 error instead of
+ 401 if auth_request and auth_basic directives were used.
+ Thanks to Jan Marc Hoffmann.
+
+ *) Bugfix: the "accept_filter" and "deferred" parameters of the "listen"
+ directive were ignored for listen sockets created during binary
+ upgrade.
+ Thanks to Piotr Sikora.
+
+ *) Bugfix: some data received from a backend with unbufferred proxy
+ might not be sent to a client immediately if "gzip" or "gunzip"
+ directives were used.
+ Thanks to Yichun Zhang.
+
+ *) Bugfix: in error handling in ngx_http_gunzip_filter_module.
+
+ *) Bugfix: responses might hang if the ngx_http_spdy_module was used
+ with the "auth_request" directive.
+
+ *) Bugfix: memory leak in nginx/Windows.
+
+
+Changes with nginx 1.5.6 01 Oct 2013
+
+ *) Feature: the "fastcgi_buffering" directive.
+
+ *) Feature: the "proxy_ssl_protocols" and "proxy_ssl_ciphers"
+ directives.
+ Thanks to Piotr Sikora.
+
+ *) Feature: optimization of SSL handshakes when using long certificate
+ chains.
+
+ *) Feature: the mail proxy supports SMTP pipelining.
*) Bugfix: in the ngx_http_auth_basic_module when using "$apr1$"
password encryption method.
Thanks to Markus Linnala.
- *) Bugfix: in the ngx_http_autoindex_module.
+ *) Bugfix: in MacOSX, Cygwin, and nginx/Windows incorrect location might
+ be used to process a request if locations were given using characters
+ in different cases.
+
+ *) Bugfix: automatic redirect with appended trailing slash for proxied
+ locations might not work.
*) Bugfix: in the mail proxy server.
+ *) Bugfix: in the ngx_http_spdy_module.
+
+
+Changes with nginx 1.5.5 17 Sep 2013
+
+ *) Change: now nginx assumes HTTP/1.0 by default if it is not able to
+ detect protocol reliably.
+
+ *) Feature: the "disable_symlinks" directive now uses O_PATH on Linux.
+
+ *) Feature: now nginx uses EPOLLRDHUP events to detect premature
+ connection close by clients if the "epoll" method is used.
+
+ *) Bugfix: in the "valid_referers" directive if the "server_names"
+ parameter was used.
+
+ *) Bugfix: the $request_time variable did not work in nginx/Windows.
+
+ *) Bugfix: in the "image_filter" directive.
+ Thanks to Lanshun Zhou.
+
+ *) Bugfix: OpenSSL 1.0.1f compatibility.
+ Thanks to Piotr Sikora.
+
+
+Changes with nginx 1.5.4 27 Aug 2013
+
+ *) Change: the "js" extension MIME type has been changed to
+ "application/javascript"; default value of the "charset_types"
+ directive was changed accordingly.
+
+ *) Change: now the "image_filter" directive with the "size" parameter
+ returns responses with the "application/json" MIME type.
-Changes with nginx 1.4.2 17 Jul 2013
+ *) Feature: the ngx_http_auth_request_module.
+
+ *) Bugfix: a segmentation fault might occur on start or during
+ reconfiguration if the "try_files" directive was used with an empty
+ parameter.
+
+ *) Bugfix: memory leak if relative paths were specified using variables
+ in the "root" or "auth_basic_user_file" directives.
+
+ *) Bugfix: the "valid_referers" directive incorrectly executed regular
+ expressions if a "Referer" header started with "https://".
+ Thanks to Liangbin Li.
+
+ *) Bugfix: responses might hang if subrequests were used and an SSL
+ handshake error happened during subrequest processing.
+ Thanks to Aviram Cohen.
+
+ *) Bugfix: in the ngx_http_autoindex_module.
+
+ *) Bugfix: in the ngx_http_spdy_module.
+
+
+Changes with nginx 1.5.3 30 Jul 2013
+
+ *) Change in internal API: now u->length defaults to -1 if working with
+ backends in unbuffered mode.
+
+ *) Change: now after receiving an incomplete response from a backend
+ server nginx tries to send an available part of the response to a
+ client, and then closes client connection.
+
+ *) Bugfix: a segmentation fault might occur in a worker process if the
+ ngx_http_spdy_module was used with the "client_body_in_file_only"
+ directive.
+
+ *) Bugfix: the "so_keepalive" parameter of the "listen" directive might
+ be handled incorrectly on DragonFlyBSD.
+ Thanks to Sepherosa Ziehau.
+
+ *) Bugfix: in the ngx_http_xslt_filter_module.
+
+ *) Bugfix: in the ngx_http_sub_filter_module.
+
+
+Changes with nginx 1.5.2 02 Jul 2013
+
+ *) Feature: now several "error_log" directives can be used.
*) Bugfix: the $r->header_in() embedded perl method did not return value
of the "Cookie" and "X-Forwarded-For" request header lines; the bug
had appeared in 1.3.14.
+ *) Bugfix: in the ngx_http_spdy_module.
+ Thanks to Jim Radford.
+
+ *) Bugfix: nginx could not be built on Linux with x32 ABI.
+ Thanks to Serguei Ivantsov.
+
+
+Changes with nginx 1.5.1 04 Jun 2013
+
+ *) Feature: the "ssi_last_modified", "sub_filter_last_modified", and
+ "xslt_last_modified" directives.
+ Thanks to Alexey Kolpakov.
+
+ *) Feature: the "http_403" parameter of the "proxy_next_upstream",
+ "fastcgi_next_upstream", "scgi_next_upstream", and
+ "uwsgi_next_upstream" directives.
+
+ *) Feature: the "allow" and "deny" directives now support unix domain
+ sockets.
+
*) Bugfix: nginx could not be built with the ngx_mail_ssl_module, but
without ngx_http_ssl_module; the bug had appeared in 1.3.14.
*) Bugfix: in the "proxy_set_body" directive.
Thanks to Lanshun Zhou.
+ *) Bugfix: in the "lingering_time" directive.
+ Thanks to Lanshun Zhou.
+
*) Bugfix: the "fail_timeout" parameter of the "server" directive in the
"upstream" context might not work if "max_fails" parameter was used;
the bug had appeared in 1.3.0.
@@ -96,11 +360,14 @@ Changes with nginx 1.4.2 17 Jul 2013
"ssl_stapling" directive was used.
Thanks to Piotr Sikora.
+ *) Bugfix: in the mail proxy server.
+ Thanks to Filipe Da Silva.
+
*) Bugfix: nginx/Windows might stop accepting connections if several
worker processes were used.
-Changes with nginx 1.4.1 07 May 2013
+Changes with nginx 1.5.0 07 May 2013
*) Security: a stack-based buffer overflow might occur in a worker
process while handling a specially crafted request, potentially
@@ -6097,7 +6364,7 @@ Changes with nginx 0.1.16 25 Jan 2005
*) Bugfix: the compressed response encrypted by SSL may not transferred
complete.
- *) Bugfix: the TCP-specific TCP_NODELAY, TCP_NOPSUH, and TCP_CORK
+ *) Bugfix: the TCP-specific TCP_NODELAY, TCP_NOPUSH, and TCP_CORK
options, are not used for the unix domain sockets.
*) Feature: the rewrite directive supports the arguments rewriting.
diff --git a/usr.sbin/nginx/CHANGES.ru b/usr.sbin/nginx/CHANGES.ru
index 2f9f3012ff5..5915dd854f2 100644
--- a/usr.sbin/nginx/CHANGES.ru
+++ b/usr.sbin/nginx/CHANGES.ru
@@ -1,5 +1,38 @@
-Изменения в nginx 1.4.7 18.03.2014
+Изменения в nginx 1.6.0 24.04.2014
+
+ *) Стабильная ветка 1.6.x.
+
+
+Изменения в nginx 1.5.13 08.04.2014
+
+ *) Изменение: улучшена обработка хэш-таблиц; в директивах
+ variables_hash_max_size и types_hash_bucket_size значения по
+ умолчанию изменены на 1024 и 64 соответственно.
+
+ *) Добавление: модуль ngx_http_mp4_module теперь понимает аргумент end.
+
+ *) Добавление: поддержка byte ranges модулем ngx_http_mp4_module и при
+ сохранении ответов в кэш.
+
+ *) Исправление: теперь nginx не пишет в лог сообщения "ngx_slab_alloc()
+ failed: no memory" при использовании разделяемой памяти в
+ ssl_session_cache и в модуле ngx_http_limit_req_module.
+
+ *) Исправление: директива underscores_in_headers не разрешала
+ подчёркивание в первом символе заголовка.
+ Спасибо Piotr Sikora.
+
+ *) Исправление: cache manager мог нагружать процессор при выходе в
+ nginx/Windows.
+
+ *) Исправление: при использовании ssl_session_cache с параметром shared
+ рабочий процесс nginx/Windows завершался аварийно.
+
+ *) Исправление: в модуле ngx_http_spdy_module.
+
+
+Изменения в nginx 1.5.12 18.03.2014
*) Безопасность: при обработке специально созданного запроса модулем
ngx_http_spdy_module могло происходить переполнение буфера в рабочем
@@ -8,11 +41,24 @@
Спасибо Lucas Molas из Programa STIC, Fundación Dr. Manuel Sadosky,
Buenos Aires, Argentina.
+ *) Добавление: параметр proxy_protocol в директивах listen и
+ real_ip_header, переменная $proxy_protocol_addr.
+
*) Исправление: в директиве fastcgi_next_upstream.
Спасибо Lucas Molas.
-Изменения в nginx 1.4.6 04.03.2014
+Изменения в nginx 1.5.11 04.03.2014
+
+ *) Безопасность: при обработке специально созданного запроса модулем
+ ngx_http_spdy_module на 32-битных платформах могла повреждаться
+ память рабочего процесса, что потенциально могло приводить к
+ выполнению произвольного кода (CVE-2014-0088); ошибка появилась в
+ 1.5.10.
+ Спасибо Lucas Molas из Programa STIC, Fundación Dr. Manuel Sadosky,
+ Buenos Aires, Argentina.
+
+ *) Добавление: переменная $ssl_session_reused.
*) Исправление: директива client_max_body_size могла не работать при
чтении тела запроса с использованием chunked transfer encoding;
@@ -22,15 +68,74 @@
*) Исправление: при проксировании WebSocket-соединений в рабочем
процессе мог произойти segmentation fault.
+ *) Исправление: в рабочем процессе мог произойти segmentation fault,
+ если использовался модуль ngx_http_spdy_module на 32-битных
+ платформах; ошибка появилась в 1.5.10.
+
+ *) Исправление: значение переменной $upstream_status могло быть
+ неверным, если использовались директивы proxy_cache_use_stale или
+ proxy_cache_revalidate.
+ Спасибо Piotr Sikora.
+
+ *) Исправление: в рабочем процессе мог произойти segmentation fault,
+ если ошибки с кодом 400 с помощью директивы error_page
+ перенаправлялись в именованный location.
+
+ *) Исправление: nginx/Windows не собирался с Visual Studio 2013.
+
+
+Изменения в nginx 1.5.10 04.02.2014
+
+ *) Добавление: модуль ngx_http_spdy_module теперь использует протокол
+ SPDY 3.1.
+ Спасибо Automattic и MaxCDN за спонсирование разработки.
+
+ *) Добавление: модуль ngx_http_mp4_module теперь пропускает дорожки,
+ имеющие меньшую длину, чем запрошенная перемотка.
+
+ *) Исправление: в рабочем процессе мог произойти segmentation fault,
+ если переменная $ssl_session_id использовалась при логгировании;
+ ошибка появилась в 1.5.9.
+
+ *) Исправление: переменные $date_local и $date_gmt использовали неверный
+ формат вне модуля ngx_http_ssi_filter_module.
+
+ *) Исправление: клиентские соединения могли сразу закрываться, если
+ использовался отложенный accept; ошибка появилась в 1.3.15.
+
+ *) Исправление: сообщения "getsockopt(TCP_FASTOPEN) ... failed"
+ записывались в лог в процессе обновления исполняемого файла на Linux;
+ ошибка появилась в 1.5.8.
+ Спасибо Piotr Sikora.
+
+
+Изменения в nginx 1.5.9 22.01.2014
+
+ *) Изменение: теперь в заголовке X-Accel-Redirect nginx ожидает
+ закодированный URI.
+
+ *) Добавление: директива ssl_buffer_size.
+
+ *) Добавление: директиву limit_rate теперь можно использовать для
+ ограничения скорости передачи ответов клиенту в SPDY-соединениях.
+
+ *) Добавление: директива spdy_chunk_size.
-Изменения в nginx 1.4.5 11.02.2014
+ *) Добавление: директива ssl_session_tickets.
+ Спасибо Dirkjan Bussink.
*) Исправление: переменная $ssl_session_id содержала всю сессию в
сериализованном виде вместо её идентификатора.
Спасибо Ivan Ristić.
- *) Исправление: клиентские соединения могли сразу закрываться, если
- использовался отложенный accept; ошибка появилась в 1.3.15.
+ *) Исправление: nginx неправильно обрабатывал закодированный символ "?"
+ в команде SSI include.
+
+ *) Исправление: модуль ngx_http_dav_module не раскодировал целевой URI
+ при обработке методов COPY и MOVE.
+
+ *) Исправление: resolver не понимал доменные имена с точкой в конце.
+ Спасибо Yichun Zhang.
*) Исправление: при проксировании в логах могли появляться сообщения
"zero size buf in output"; ошибка появилась в 1.3.9.
@@ -42,53 +147,219 @@
poll и /dev/poll проксируемые WebSocket-соединения могли зависать
сразу после открытия.
+ *) Исправление: директива xclient почтового прокси-сервера некорректно
+ передавала IPv6-адреса.
+
+
+Изменения в nginx 1.5.8 17.12.2013
+
+ *) Добавление: теперь resolver поддерживает IPv6.
+
+ *) Добавление: директива listen поддерживает параметр fastopen.
+ Спасибо Mathew Rodley.
+
+ *) Добавление: поддержка SSL в модуле ngx_http_uwsgi_module.
+ Спасибо Roberto De Ioris.
+
+ *) Добавление: скрипты подсветки синтаксиса для vim добавлены в contrib.
+ Спасибо Evan Miller.
+
*) Исправление: при чтении тела запроса с использованием chunked
transfer encoding по SSL-соединению мог произойти таймаут.
- *) Исправление: утечки памяти в nginx/Windows.
+ *) Исправление: директива master_process работала неправильно в
+ nginx/Windows.
+
+ *) Исправление: параметр setfib директивы listen мог не работать.
+
+ *) Исправление: в модуле ngx_http_spdy_module.
-Изменения в nginx 1.4.4 19.11.2013
+Изменения в nginx 1.5.7 19.11.2013
*) Безопасность: символ, следующий за незакодированным пробелом в строке
запроса, обрабатывался неправильно (CVE-2013-4547); ошибка появилась
в 0.8.41.
Спасибо Ivan Fratric из Google Security Team.
+ *) Изменение: уровень логгирования ошибок auth_basic об отсутствии
+ пароля понижен с уровня error до info.
-Изменения в nginx 1.4.3 08.10.2013
+ *) Добавление: директивы proxy_cache_revalidate,
+ fastcgi_cache_revalidate, scgi_cache_revalidate и
+ uwsgi_cache_revalidate.
- *) Исправление: в рабочем процессе мог произойти segmentation fault,
- если использовался модуль ngx_http_spdy_module и директива
- client_body_in_file_only.
+ *) Добавление: директива ssl_session_ticket_key.
+ Спасибо Piotr Sikora.
- *) Исправление: на старте или во время переконфигурации мог произойти
- segmentation fault, если использовалась директива try_files с пустым
- параметром.
+ *) Исправление: директива "add_header Cache-Control ''" добавляла строку
+ заголовка ответа "Cache-Control" с пустым значением.
- *) Исправление: переменная $request_time не работала в nginx/Windows.
+ *) Исправление: директива "satisfy any" могла вернуть ошибку 403 вместо
+ 401 при использовании директив auth_request и auth_basic.
+ Спасибо Jan Marc Hoffmann.
+
+ *) Исправление: параметры accept_filter и deferred директивы listen
+ игнорировались для listen-сокетов, создаваемых в процессе обновления
+ исполняемого файла.
+ Спасибо Piotr Sikora.
+
+ *) Исправление: часть данных, полученных от бэкенда при
+ небуферизированном проксировании, могла не отправляться клиенту
+ сразу, если использовались директивы gzip или gunzip.
+ Спасибо Yichun Zhang.
+
+ *) Исправление: в обработке ошибок в модуле
+ ngx_http_gunzip_filter_module.
+
+ *) Исправление: ответы могли зависать, если использовался модуль
+ ngx_http_spdy_module и директива auth_request.
+
+ *) Исправление: утечки памяти в nginx/Windows.
+
+
+Изменения в nginx 1.5.6 01.10.2013
+
+ *) Добавление: директива fastcgi_buffering.
+
+ *) Добавление: директивы proxy_ssl_protocols и proxy_ssl_ciphers.
+ Спасибо Piotr Sikora.
+
+ *) Добавление: оптимизация SSL handshake при использовании длинных
+ цепочек сертификатов.
+
+ *) Добавление: почтовый прокси-сервер поддерживает SMTP pipelining.
*) Исправление: в модуле ngx_http_auth_basic_module при использовании
метода шифрования паролей "$apr1$".
Спасибо Markus Linnala.
- *) Исправление: в модуле ngx_http_autoindex_module.
+ *) Исправление: на MacOSX, Cygwin и nginx/Windows для обработки запроса
+ мог использоваться неверный location, если для задания location'ов
+ использовались символы разных регистров.
+
+ *) Исправление: автоматическое перенаправление с добавлением
+ завершающего слэша для проксированных location'ов могло не работать.
*) Исправление: в почтовом прокси-сервере.
+ *) Исправление: в модуле ngx_http_spdy_module.
+
+
+Изменения в nginx 1.5.5 17.09.2013
-Изменения в nginx 1.4.2 17.07.2013
+ *) Изменение: теперь nginx по умолчанию использует HTTP/1.0, если точно
+ определить протокол не удалось.
+
+ *) Добавление: директива disable_symlinks теперь использует O_PATH на
+ Linux.
+
+ *) Добавление: для определения того, что клиент закрыл соединение, при
+ использовании метода epoll теперь используются события EPOLLRDHUP.
+
+ *) Исправление: в директиве valid_referers при использовании параметра
+ server_names.
+
+ *) Исправление: переменная $request_time не работала в nginx/Windows.
+
+ *) Исправление: в директиве image_filter.
+ Спасибо Lanshun Zhou.
+
+ *) Исправление: совместимость с OpenSSL 1.0.1f.
+ Спасибо Piotr Sikora.
+
+
+Изменения в nginx 1.5.4 27.08.2013
+
+ *) Изменение: MIME-тип для расширения js изменён на
+ "application/javascript"; значение по умолчанию директивы
+ charset_types изменено соответственно.
+
+ *) Изменение: теперь директива image_filter с параметром size возвращает
+ ответ с MIME-типом "application/json".
+
+ *) Добавление: модуль ngx_http_auth_request_module.
+
+ *) Исправление: на старте или во время переконфигурации мог произойти
+ segmentation fault, если использовалась директива try_files с пустым
+ параметром.
+
+ *) Исправление: утечки памяти при использовании в директивах root и
+ auth_basic_user_file относительных путей, заданных с помощью
+ переменных.
+
+ *) Исправление: директива valid_referers неправильно выполняла
+ регулярные выражения, если заголовок Referer начинался с "https://".
+ Спасибо Liangbin Li.
+
+ *) Исправление: ответы могли зависать, если использовались подзапросы и
+ при обработке подзапроса происходила ошибка во время SSL handshake с
+ бэкендом.
+ Спасибо Aviram Cohen.
+
+ *) Исправление: в модуле ngx_http_autoindex_module.
+
+ *) Исправление: в модуле ngx_http_spdy_module.
+
+
+Изменения в nginx 1.5.3 30.07.2013
+
+ *) Изменение во внутреннем API: теперь при небуферизированной работе с
+ бэкендами u->length по умолчанию устанавливается в -1.
+
+ *) Изменение: теперь при получении неполного ответа от бэкенда nginx
+ отправляет полученную часть ответа, после чего закрывает соединение с
+ клиентом.
+
+ *) Исправление: в рабочем процессе мог произойти segmentation fault,
+ если использовался модуль ngx_http_spdy_module и директива
+ client_body_in_file_only.
+
+ *) Исправление: параметр so_keepalive директивы listen мог работать
+ некорректно на DragonFlyBSD.
+ Спасибо Sepherosa Ziehau.
+
+ *) Исправление: в модуле ngx_http_xslt_filter_module.
+
+ *) Исправление: в модуле ngx_http_sub_filter_module.
+
+
+Изменения в nginx 1.5.2 02.07.2013
+
+ *) Добавление: теперь можно использовать несколько директив error_log.
*) Исправление: метод $r->header_in() встроенного перла не возвращал
значения строк "Cookie" и "X-Forwarded-For" из заголовка запроса;
ошибка появилась в 1.3.14.
+ *) Исправление: в модуле ngx_http_spdy_module.
+ Спасибо Jim Radford.
+
+ *) Исправление: nginx не собирался на Linux при использовании x32 ABI.
+ Спасибо Сергею Иванцову.
+
+
+Изменения в nginx 1.5.1 04.06.2013
+
+ *) Добавление: директивы ssi_last_modified, sub_filter_last_modified и
+ xslt_last_modified.
+ Спасибо Алексею Колпакову.
+
+ *) Добавление: параметр http_403 в директивах proxy_next_upstream,
+ fastcgi_next_upstream, scgi_next_upstream и uwsgi_next_upstream.
+
+ *) Добавление: директивы allow и deny теперь поддерживают unix domain
+ сокеты.
+
*) Исправление: nginx не собирался с модулем ngx_mail_ssl_module, но без
модуля ngx_http_ssl_module; ошибка появилась в 1.3.14.
*) Исправление: в директиве proxy_set_body.
Спасибо Lanshun Zhou.
+ *) Исправление: в директиве lingering_time.
+ Спасибо Lanshun Zhou.
+
*) Исправление: параметр fail_timeout директивы server в блоке upstream
мог не работать, если использовался параметр max_fails; ошибка
появилась в 1.3.0.
@@ -97,11 +368,14 @@
если использовалась директива ssl_stapling.
Спасибо Piotr Sikora.
+ *) Исправление: в почтовом прокси-сервере.
+ Спасибо Filipe Da Silva.
+
*) Исправление: nginx/Windows мог перестать принимать соединения, если
использовалось несколько рабочих процессов.
-Изменения в nginx 1.4.1 07.05.2013
+Изменения в nginx 1.5.0 07.05.2013
*) Безопасность: при обработке специально созданного запроса мог
перезаписываться стек рабочего процесса, что могло приводить к
@@ -427,7 +701,7 @@
*) Изменение: параметр single директивы keepalive теперь игнорируется.
*) Изменение: сжатие SSL теперь отключено в том числе при использовании
- OpenSSL cтарее 1.0.0.
+ OpenSSL старее 1.0.0.
*) Добавление: директиву "ip_hash" теперь можно использовать для
балансировки IPv6 клиентов.
@@ -2704,7 +2978,7 @@
умолчанию; ошибка появилась в 0.7.18.
Спасибо Максиму Дунину.
- *) Исправление: при проксировании SMPT nginx выдавал сообщение
+ *) Исправление: при проксировании SMTP nginx выдавал сообщение
"250 2.0.0 OK" вместо "235 2.0.0 OK"; ошибка появилась в 0.7.22.
Спасибо Максиму Дунину.
@@ -6190,7 +6464,7 @@
*) Исправление: при использовании SSL сжатый ответ мог передаваться не
до конца.
- *) Исправление: опции TCP_NODELAY, TCP_NOPSUH и TCP_CORK, специфичные
+ *) Исправление: опции TCP_NODELAY, TCP_NOPUSH и TCP_CORK, специфичные
для TCP сокетов, не используются для unix domain сокетов.
*) Добавление: директива rewrite поддерживает перезаписывание
@@ -6254,7 +6528,7 @@
*) Изменение: если в URI встречался символ %3F, то он считался началом
строки аргументов.
- *) Добавление: поддержка unix domain сoкетов в модуле
+ *) Добавление: поддержка unix domain сокетов в модуле
ngx_http_proxy_module.
*) Добавление: директивы ssl_engine и ssl_ciphers.
diff --git a/usr.sbin/nginx/Makefile.bsd-wrapper b/usr.sbin/nginx/Makefile.bsd-wrapper
index f09b516d6a1..a9321ca953b 100644
--- a/usr.sbin/nginx/Makefile.bsd-wrapper
+++ b/usr.sbin/nginx/Makefile.bsd-wrapper
@@ -1,5 +1,5 @@
# Build wrapper for Nginx
-# $OpenBSD: Makefile.bsd-wrapper,v 1.16 2014/05/18 05:27:49 jsg Exp $
+# $OpenBSD: Makefile.bsd-wrapper,v 1.17 2014/06/12 15:27:08 robert Exp $
LNDIR= /usr/bin/lndir
@@ -23,7 +23,6 @@ CONFIGURE_ARGS= --prefix=/var/www \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-ipv6 \
- --with-cc-opt="-DNGX_ENABLE_SYSLOG" \
--without-mail_pop3_module \
--without-mail_imap_module \
--without-mail_smtp_module
diff --git a/usr.sbin/nginx/auto/cc/clang b/usr.sbin/nginx/auto/cc/clang
index 9f60d7b3a2b..baaf4baa23a 100644
--- a/usr.sbin/nginx/auto/cc/clang
+++ b/usr.sbin/nginx/auto/cc/clang
@@ -5,8 +5,8 @@
# clang
-NGX_CLANG_VER=`$CC -v 2>&1 | grep 'clang version' 2>&1 \
- | sed -e 's/^.*clang version \(.*\)/\1/'`
+NGX_CLANG_VER=`$CC -v 2>&1 | grep '\(clang\|LLVM\) version' 2>&1 \
+ | sed -e 's/^.* version \(.*\)/\1/'`
echo " + clang version: $NGX_CLANG_VER"
@@ -82,13 +82,14 @@ fi
# warnings
CFLAGS="$CFLAGS $NGX_CLANG_OPT -Wall -Wextra -Wpointer-arith"
+CFLAGS="$CFLAGS -Wconditional-uninitialized"
#CFLAGS="$CFLAGS -Wmissing-prototypes"
# we have a lot of unused function arguments
CFLAGS="$CFLAGS -Wno-unused-parameter"
# stop on warning
-#CFLAGS="$CFLAGS -Werror"
+CFLAGS="$CFLAGS -Werror"
# debug
CFLAGS="$CFLAGS -g"
diff --git a/usr.sbin/nginx/auto/cc/conf b/usr.sbin/nginx/auto/cc/conf
index 8027b980502..edc6d74ddfa 100644
--- a/usr.sbin/nginx/auto/cc/conf
+++ b/usr.sbin/nginx/auto/cc/conf
@@ -43,6 +43,29 @@ if test -n "$CFLAGS"; then
ngx_include_opt="-I"
;;
+ sunc)
+
+ case "$NGX_MACHINE" in
+
+ i86pc)
+ NGX_AUX=" src/os/unix/ngx_sunpro_x86.il"
+ ;;
+
+ sun4u | sun4v)
+ NGX_AUX=" src/os/unix/ngx_sunpro_sparc64.il"
+ ;;
+
+ esac
+
+ case $CPU in
+
+ amd64)
+ NGX_AUX=" src/os/unix/ngx_sunpro_amd64.il"
+ ;;
+
+ esac
+ ;;
+
esac
else
diff --git a/usr.sbin/nginx/auto/cc/msvc b/usr.sbin/nginx/auto/cc/msvc
index 1bf675e19e9..393ba321499 100644
--- a/usr.sbin/nginx/auto/cc/msvc
+++ b/usr.sbin/nginx/auto/cc/msvc
@@ -106,6 +106,7 @@ fi
# precompiled headers
CORE_DEPS="$CORE_DEPS $NGX_OBJS/ngx_config.pch"
+CORE_LINK="$CORE_LINK $NGX_OBJS/ngx_pch.obj"
NGX_PCH="$NGX_OBJS/ngx_config.pch"
NGX_BUILD_PCH="-Ycngx_config.h -Fp$NGX_OBJS/ngx_config.pch"
NGX_USE_PCH="-Yungx_config.h -Fp$NGX_OBJS/ngx_config.pch"
diff --git a/usr.sbin/nginx/auto/cc/name b/usr.sbin/nginx/auto/cc/name
index 7a5656c6475..51a7ed92e1d 100644
--- a/usr.sbin/nginx/auto/cc/name
+++ b/usr.sbin/nginx/auto/cc/name
@@ -67,7 +67,7 @@ elif `$CC -v 2>&1 | grep 'gcc version' >/dev/null 2>&1`; then
NGX_CC_NAME=gcc
echo " + using GNU C compiler"
-elif `$CC -v 2>&1 | grep 'clang version' >/dev/null 2>&1`; then
+elif `$CC -v 2>&1 | grep '\(clang\|LLVM\) version' >/dev/null 2>&1`; then
NGX_CC_NAME=clang
echo " + using Clang C compiler"
diff --git a/usr.sbin/nginx/auto/cc/owc b/usr.sbin/nginx/auto/cc/owc
index 22eb4c1259a..a063aa34121 100644
--- a/usr.sbin/nginx/auto/cc/owc
+++ b/usr.sbin/nginx/auto/cc/owc
@@ -65,10 +65,10 @@ have=NGX_HAVE_C99_VARIADIC_MACROS . auto/have
# the precompiled headers
-CORE_DEPS="$CORE_DEPS $NGX_OBJS/ngx_config.pch"
-NGX_PCH="$NGX_OBJS/ngx_config.pch"
-NGX_BUILD_PCH="-fhq=$NGX_OBJS/ngx_config.pch"
-NGX_USE_PCH="-fh=$NGX_OBJS/ngx_config.pch"
+#CORE_DEPS="$CORE_DEPS $NGX_OBJS/ngx_config.pch"
+#NGX_PCH="$NGX_OBJS/ngx_config.pch"
+#NGX_BUILD_PCH="-fhq=$NGX_OBJS/ngx_config.pch"
+#NGX_USE_PCH="-fh=$NGX_OBJS/ngx_config.pch"
# the link flags, built target is NT GUI mode application
diff --git a/usr.sbin/nginx/auto/cc/sunc b/usr.sbin/nginx/auto/cc/sunc
index dd9ccedfbaa..8f12d7cd7fe 100644
--- a/usr.sbin/nginx/auto/cc/sunc
+++ b/usr.sbin/nginx/auto/cc/sunc
@@ -30,7 +30,7 @@ if [ -x $NGX_AUTOTEST ]; then
ngx_sunc_ver=`$NGX_AUTOTEST`
fi
-rm $NGX_AUTOTEST*
+rm -rf $NGX_AUTOTEST*
# 1424 == 0x590, Sun Studio 12
diff --git a/usr.sbin/nginx/auto/endianness b/usr.sbin/nginx/auto/endianness
index 87311a0f16e..93da2f80d99 100644
--- a/usr.sbin/nginx/auto/endianness
+++ b/usr.sbin/nginx/auto/endianness
@@ -34,10 +34,10 @@ if [ -x $NGX_AUTOTEST ]; then
echo " big endian"
fi
- rm $NGX_AUTOTEST*
+ rm -rf $NGX_AUTOTEST*
else
- rm $NGX_AUTOTEST*
+ rm -rf $NGX_AUTOTEST*
echo
echo "$0: error: cannot detect system byte ordering"
diff --git a/usr.sbin/nginx/auto/feature b/usr.sbin/nginx/auto/feature
index c13e51dfb82..1145f28684b 100644
--- a/usr.sbin/nginx/auto/feature
+++ b/usr.sbin/nginx/auto/feature
@@ -120,4 +120,4 @@ else
echo "----------" >> $NGX_AUTOCONF_ERR
fi
-rm $NGX_AUTOTEST*
+rm -rf $NGX_AUTOTEST*
diff --git a/usr.sbin/nginx/auto/include b/usr.sbin/nginx/auto/include
index 3466fda15b3..e34dabdae1d 100644
--- a/usr.sbin/nginx/auto/include
+++ b/usr.sbin/nginx/auto/include
@@ -58,4 +58,4 @@ else
echo "----------" >> $NGX_AUTOCONF_ERR
fi
-rm $NGX_AUTOTEST*
+rm -rf $NGX_AUTOTEST*
diff --git a/usr.sbin/nginx/auto/lib/libatomic/make b/usr.sbin/nginx/auto/lib/libatomic/make
index 023ed18fb98..c90318ea122 100644
--- a/usr.sbin/nginx/auto/lib/libatomic/make
+++ b/usr.sbin/nginx/auto/lib/libatomic/make
@@ -9,6 +9,8 @@ $NGX_LIBATOMIC/src/libatomic_ops.a: $NGX_LIBATOMIC/Makefile
cd $NGX_LIBATOMIC && \$(MAKE)
$NGX_LIBATOMIC/Makefile: $NGX_MAKEFILE
- cd $NGX_LIBATOMIC && ./configure
+ cd $NGX_LIBATOMIC \\
+ && if [ -f Makefile ]; then \$(MAKE) distclean; fi \\
+ && ./configure
END
diff --git a/usr.sbin/nginx/auto/lib/openssl/conf b/usr.sbin/nginx/auto/lib/openssl/conf
index 528ee1794e9..a65815f6364 100644
--- a/usr.sbin/nginx/auto/lib/openssl/conf
+++ b/usr.sbin/nginx/auto/lib/openssl/conf
@@ -33,6 +33,10 @@ if [ $OPENSSL != NONE ]; then
CORE_LIBS="$CORE_LIBS $OPENSSL/.openssl/lib/libssl.a"
CORE_LIBS="$CORE_LIBS $OPENSSL/.openssl/lib/libcrypto.a"
CORE_LIBS="$CORE_LIBS $NGX_LIBDL"
+
+ if [ "$NGX_PLATFORM" = win32 ]; then
+ CORE_LIBS="$CORE_LIBS -lgdi32 -lcrypt32 -lws2_32"
+ fi
;;
esac
diff --git a/usr.sbin/nginx/auto/lib/openssl/make b/usr.sbin/nginx/auto/lib/openssl/make
index 9090fcbfd34..e64acd973ec 100644
--- a/usr.sbin/nginx/auto/lib/openssl/make
+++ b/usr.sbin/nginx/auto/lib/openssl/make
@@ -55,7 +55,7 @@ END
$OPENSSL/.openssl/include/openssl/ssl.h: $NGX_MAKEFILE
cd $OPENSSL \\
- && \$(MAKE) clean \\
+ && if [ -f Makefile ]; then \$(MAKE) clean; fi \\
&& ./config --prefix=$ngx_prefix no-shared $OPENSSL_OPT \\
&& \$(MAKE) \\
&& \$(MAKE) install LIBDIR=lib
diff --git a/usr.sbin/nginx/auto/lib/pcre/conf b/usr.sbin/nginx/auto/lib/pcre/conf
index 69e87ea77b2..eeecffb0dc9 100644
--- a/usr.sbin/nginx/auto/lib/pcre/conf
+++ b/usr.sbin/nginx/auto/lib/pcre/conf
@@ -73,6 +73,11 @@ if [ $PCRE != NONE ]; then
*)
have=NGX_PCRE . auto/have
+
+ if [ "$NGX_PLATFORM" = win32 ]; then
+ have=PCRE_STATIC . auto/have
+ fi
+
CORE_DEPS="$CORE_DEPS $PCRE/pcre.h"
LINK_DEPS="$LINK_DEPS $PCRE/.libs/libpcre.a"
CORE_LIBS="$CORE_LIBS $PCRE/.libs/libpcre.a"
diff --git a/usr.sbin/nginx/auto/lib/pcre/make b/usr.sbin/nginx/auto/lib/pcre/make
index 834779b9cce..0a27a112c11 100644
--- a/usr.sbin/nginx/auto/lib/pcre/make
+++ b/usr.sbin/nginx/auto/lib/pcre/make
@@ -23,16 +23,19 @@ case "$NGX_CC_NAME" in
ngx_pcre=`echo \-DPCRE=\"$PCRE\" | sed -e "s/\//$ngx_regex_dirsep/g"`
;;
-esac
+ *)
+ ngx_makefile=
+ ;;
+esac
-case "$NGX_PLATFORM" in
- win32)
+if [ -n "$ngx_makefile" ]; then
- cat << END >> $NGX_MAKEFILE
+ cat << END >> $NGX_MAKEFILE
-`echo "$PCRE/pcre.lib: $NGX_MAKEFILE" | sed -e "s/\//$ngx_regex_dirsep/g"`
+`echo "$PCRE/pcre.lib: $PCRE/pcre.h $NGX_MAKEFILE" \
+ | sed -e "s/\//$ngx_regex_dirsep/g"`
\$(MAKE) -f auto/lib/pcre/$ngx_makefile $ngx_pcre $ngx_opt
`echo "$PCRE/pcre.h:" | sed -e "s/\//$ngx_regex_dirsep/g"`
@@ -40,10 +43,9 @@ case "$NGX_PLATFORM" in
END
- ;;
+else
- *)
- cat << END >> $NGX_MAKEFILE
+ cat << END >> $NGX_MAKEFILE
$PCRE/pcre.h: $PCRE/Makefile
@@ -59,6 +61,4 @@ $PCRE/.libs/libpcre.a: $PCRE/Makefile
END
- ;;
-
-esac
+fi
diff --git a/usr.sbin/nginx/auto/lib/pcre/makefile.bcc b/usr.sbin/nginx/auto/lib/pcre/makefile.bcc
index 1c140d668b7..7a0f2beafc6 100644
--- a/usr.sbin/nginx/auto/lib/pcre/makefile.bcc
+++ b/usr.sbin/nginx/auto/lib/pcre/makefile.bcc
@@ -4,7 +4,8 @@
CFLAGS = -q -O2 -tWM -w-8004 $(CPU_OPT)
-PCREFLAGS = -DHAVE_CONFIG_H -DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10
+PCREFLAGS = -DHAVE_CONFIG_H -DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10 \
+ -DSUPPORT_PCRE8 -DHAVE_MEMMOVE
pcre.lib:
@@ -12,8 +13,8 @@ pcre.lib:
bcc32 -c $(CFLAGS) -I. $(PCREFLAGS) pcre_*.c
- > pcre.lst
- for %n in (*.obj) do @echo +%n & >> pcre.lst
+ copy /y nul pcre.lst
+ for %n in (*.obj) do @echo +%n ^^& >> pcre.lst
echo + >> pcre.lst
tlib pcre.lib @pcre.lst
diff --git a/usr.sbin/nginx/auto/lib/pcre/makefile.msvc b/usr.sbin/nginx/auto/lib/pcre/makefile.msvc
index 7a8da715818..07fd9a2853a 100644
--- a/usr.sbin/nginx/auto/lib/pcre/makefile.msvc
+++ b/usr.sbin/nginx/auto/lib/pcre/makefile.msvc
@@ -4,7 +4,8 @@
CFLAGS = -O2 -Ob1 -Oi -Gs $(LIBC) $(CPU_OPT)
-PCREFLAGS = -DHAVE_CONFIG_H -DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10
+PCREFLAGS = -DHAVE_CONFIG_H -DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10 \
+ -DSUPPORT_PCRE8 -DHAVE_MEMMOVE
pcre.lib:
diff --git a/usr.sbin/nginx/auto/lib/pcre/makefile.owc b/usr.sbin/nginx/auto/lib/pcre/makefile.owc
index bfb69206879..122fd5b27f2 100644
--- a/usr.sbin/nginx/auto/lib/pcre/makefile.owc
+++ b/usr.sbin/nginx/auto/lib/pcre/makefile.owc
@@ -4,7 +4,8 @@
CFLAGS = -c -zq -bt=nt -ot -op -oi -oe -s -bm $(CPU_OPT)
-PCREFLAGS = -DHAVE_CONFIG_H -DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10
+PCREFLAGS = -DHAVE_CONFIG_H -DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10 &
+ -DSUPPORT_PCRE8 -DHAVE_MEMMOVE
pcre.lib:
diff --git a/usr.sbin/nginx/auto/lib/perl/make b/usr.sbin/nginx/auto/lib/perl/make
index 260bd95a0b7..d1c1b9e48c1 100644
--- a/usr.sbin/nginx/auto/lib/perl/make
+++ b/usr.sbin/nginx/auto/lib/perl/make
@@ -18,6 +18,7 @@ $NGX_OBJS/src/http/modules/perl/blib/arch/auto/nginx/nginx.$ngx_perl_dlext: \\
$NGX_OBJS/src/http/modules/perl/Makefile: \\
+ $NGX_AUTO_CONFIG_H \\
src/core/nginx.h \\
src/http/modules/perl/Makefile.PL \\
src/http/modules/perl/nginx.pm \\
diff --git a/usr.sbin/nginx/auto/lib/test b/usr.sbin/nginx/auto/lib/test
index 907e2353b7f..ba943a29d40 100644
--- a/usr.sbin/nginx/auto/lib/test
+++ b/usr.sbin/nginx/auto/lib/test
@@ -37,4 +37,4 @@ else
echo " not found"
fi
-rm $NGX_AUTOTEST*
+rm -rf $NGX_AUTOTEST*
diff --git a/usr.sbin/nginx/auto/lib/zlib/make b/usr.sbin/nginx/auto/lib/zlib/make
index 9401a1d1a8e..7875ef67fe0 100644
--- a/usr.sbin/nginx/auto/lib/zlib/make
+++ b/usr.sbin/nginx/auto/lib/zlib/make
@@ -24,6 +24,10 @@ case "$NGX_CC_NAME" in
ngx_zlib=`echo \-DZLIB=\"$ZLIB\" | sed -e "s/\//$ngx_regex_dirsep/g"`
;;
+ *)
+ ngx_makefile=
+ ;;
+
esac
@@ -33,13 +37,30 @@ done=NO
case "$NGX_PLATFORM" in
win32)
- cat << END >> $NGX_MAKEFILE
+
+ if [ -n "$ngx_makefile" ]; then
+ cat << END >> $NGX_MAKEFILE
`echo "$ZLIB/zlib.lib: $NGX_MAKEFILE" | sed -e "s/\//$ngx_regex_dirsep/g"`
\$(MAKE) -f auto/lib/zlib/$ngx_makefile $ngx_opt $ngx_zlib
END
+ else
+
+ cat << END >> $NGX_MAKEFILE
+
+$ZLIB/libz.a: $NGX_MAKEFILE
+ cd $ZLIB \\
+ && \$(MAKE) distclean \\
+ && \$(MAKE) -f win32/Makefile.gcc \\
+ CFLAGS="$ZLIB_OPT" CC="\$(CC)" \\
+ libz.a
+
+END
+
+ fi
+
done=YES
;;
diff --git a/usr.sbin/nginx/auto/modules b/usr.sbin/nginx/auto/modules
index a78e785e5c0..e1eda943fd3 100644
--- a/usr.sbin/nginx/auto/modules
+++ b/usr.sbin/nginx/auto/modules
@@ -42,6 +42,7 @@ fi
if [ $NGX_TEST_BUILD_EPOLL = YES ]; then
have=NGX_HAVE_EPOLL . auto/have
+ have=NGX_HAVE_EPOLLRDHUP . auto/have
have=NGX_HAVE_EVENTFD . auto/have
have=NGX_TEST_BUILD_EPOLL . auto/have
EVENT_MODULES="$EVENT_MODULES $EPOLL_MODULE"
@@ -220,6 +221,11 @@ if [ $HTTP_RANDOM_INDEX = YES ]; then
HTTP_SRCS="$HTTP_SRCS $HTTP_RANDOM_INDEX_SRCS"
fi
+if [ $HTTP_AUTH_REQUEST = YES ]; then
+ HTTP_MODULES="$HTTP_MODULES $HTTP_AUTH_REQUEST_MODULE"
+ HTTP_SRCS="$HTTP_SRCS $HTTP_AUTH_REQUEST_SRCS"
+fi
+
if [ $HTTP_AUTH_BASIC = YES ]; then
USE_MD5=YES
USE_SHA1=YES
@@ -477,6 +483,8 @@ if [ $MAIL = YES ]; then
modules="$modules $MAIL_PROXY_MODULE"
MAIL_SRCS="$MAIL_SRCS $MAIL_PROXY_SRCS"
+
+ NGX_ADDON_DEPS="$NGX_ADDON_DEPS \$(MAIL_DEPS)"
fi
diff --git a/usr.sbin/nginx/auto/options b/usr.sbin/nginx/auto/options
index 6713379e3b9..6cea8c7c200 100644
--- a/usr.sbin/nginx/auto/options
+++ b/usr.sbin/nginx/auto/options
@@ -71,6 +71,7 @@ HTTP_ADDITION=NO
HTTP_DAV=NO
HTTP_ACCESS=YES
HTTP_AUTH_BASIC=YES
+HTTP_AUTH_REQUEST=NO
HTTP_USERID=YES
HTTP_AUTOINDEX=YES
HTTP_RANDOM_INDEX=NO
@@ -215,6 +216,7 @@ do
--with-http_mp4_module) HTTP_MP4=YES ;;
--with-http_gunzip_module) HTTP_GUNZIP=YES ;;
--with-http_gzip_static_module) HTTP_GZIP_STATIC=YES ;;
+ --with-http_auth_request_module) HTTP_AUTH_REQUEST=YES ;;
--with-http_random_index_module) HTTP_RANDOM_INDEX=YES ;;
--with-http_secure_link_module) HTTP_SECURE_LINK=YES ;;
--with-http_degradation_module) HTTP_DEGRADATION=YES ;;
@@ -363,6 +365,7 @@ cat << END
--with-http_mp4_module enable ngx_http_mp4_module
--with-http_gunzip_module enable ngx_http_gunzip_module
--with-http_gzip_static_module enable ngx_http_gzip_static_module
+ --with-http_auth_request_module enable ngx_http_auth_request_module
--with-http_random_index_module enable ngx_http_random_index_module
--with-http_secure_link_module enable ngx_http_secure_link_module
--with-http_degradation_module enable ngx_http_degradation_module
diff --git a/usr.sbin/nginx/auto/os/darwin b/usr.sbin/nginx/auto/os/darwin
index 590e03697db..b97518a6ea0 100644
--- a/usr.sbin/nginx/auto/os/darwin
+++ b/usr.sbin/nginx/auto/os/darwin
@@ -112,5 +112,5 @@ ngx_feature_incs="#include <libkern/OSAtomic.h>"
ngx_feature_path=
ngx_feature_libs=
ngx_feature_test="int32_t lock, n;
- n = OSAtomicCompareAndSwap32Barrier(0, 1, lock)"
+ n = OSAtomicCompareAndSwap32Barrier(0, 1, &lock)"
. auto/feature
diff --git a/usr.sbin/nginx/auto/os/linux b/usr.sbin/nginx/auto/os/linux
index c506d3dc3ad..19bf832ce3e 100644
--- a/usr.sbin/nginx/auto/os/linux
+++ b/usr.sbin/nginx/auto/os/linux
@@ -65,9 +65,41 @@ if [ $ngx_found = yes ]; then
CORE_SRCS="$CORE_SRCS $EPOLL_SRCS"
EVENT_MODULES="$EVENT_MODULES $EPOLL_MODULE"
EVENT_FOUND=YES
+
+
+ # EPOLLRDHUP appeared in Linux 2.6.17, glibc 2.8
+
+ ngx_feature="EPOLLRDHUP"
+ ngx_feature_name="NGX_HAVE_EPOLLRDHUP"
+ ngx_feature_run=no
+ ngx_feature_incs="#include <sys/epoll.h>"
+ ngx_feature_path=
+ ngx_feature_libs=
+ ngx_feature_test="int efd = 0, fd = 0;
+ struct epoll_event ee;
+ ee.events = EPOLLIN|EPOLLRDHUP|EPOLLET;
+ ee.data.ptr = NULL;
+ epoll_ctl(efd, EPOLL_CTL_ADD, fd, &ee)"
+ . auto/feature
fi
+# O_PATH and AT_EMPTY_PATH were introduced in 2.6.39, glibc 2.14
+
+ngx_feature="O_PATH"
+ngx_feature_name="NGX_HAVE_O_PATH"
+ngx_feature_run=no
+ngx_feature_incs="#include <sys/types.h>
+ #include <sys/stat.h>
+ #include <fcntl.h>"
+ngx_feature_path=
+ngx_feature_libs=
+ngx_feature_test="int fd; struct stat sb;
+ fd = openat(AT_FDCWD, \".\", O_PATH|O_DIRECTORY|O_NOFOLLOW);
+ if (fstatat(fd, \"\", &sb, AT_EMPTY_PATH) != 0) return 1"
+. auto/feature
+
+
# sendfile()
CC_AUX_FLAGS="$cc_aux_flags -D_GNU_SOURCE"
diff --git a/usr.sbin/nginx/auto/os/win32 b/usr.sbin/nginx/auto/os/win32
index 21a54ba11e5..0b9b461875f 100644
--- a/usr.sbin/nginx/auto/os/win32
+++ b/usr.sbin/nginx/auto/os/win32
@@ -9,10 +9,21 @@ CORE_INCS="$WIN32_INCS"
CORE_DEPS="$WIN32_DEPS"
CORE_SRCS="$WIN32_SRCS $IOCP_SRCS"
OS_CONFIG="$WIN32_CONFIG"
-CORE_LIBS="$CORE_LIBS advapi32.lib ws2_32.lib"
NGX_ICONS="$NGX_WIN32_ICONS"
SELECT_SRCS=$WIN32_SELECT_SRCS
+case "$NGX_CC_NAME" in
+
+ gcc)
+ CORE_LIBS="$CORE_LIBS -ladvapi32 -lws2_32"
+ ;;
+
+ *)
+ CORE_LIBS="$CORE_LIBS advapi32.lib ws2_32.lib"
+ ;;
+
+esac
+
EVENT_MODULES="$EVENT_MODULES $IOCP_MODULE"
EVENT_FOUND=YES
diff --git a/usr.sbin/nginx/auto/sources b/usr.sbin/nginx/auto/sources
index 56701ebb973..613a39a17e4 100644
--- a/usr.sbin/nginx/auto/sources
+++ b/usr.sbin/nginx/auto/sources
@@ -36,7 +36,9 @@ CORE_DEPS="src/core/nginx.h \
src/core/ngx_conf_file.h \
src/core/ngx_resolver.h \
src/core/ngx_open_file_cache.h \
- src/core/ngx_crypt.h"
+ src/core/ngx_crypt.h \
+ src/core/ngx_proxy_protocol.h \
+ src/core/ngx_syslog.h"
CORE_SRCS="src/core/nginx.c \
@@ -67,7 +69,9 @@ CORE_SRCS="src/core/nginx.c \
src/core/ngx_conf_file.c \
src/core/ngx_resolver.c \
src/core/ngx_open_file_cache.c \
- src/core/ngx_crypt.c"
+ src/core/ngx_crypt.c \
+ src/core/ngx_proxy_protocol.c \
+ src/core/ngx_syslog.c"
REGEX_MODULE=ngx_regex_module
@@ -398,6 +402,10 @@ HTTP_AUTH_BASIC_MODULE=ngx_http_auth_basic_module
HTTP_AUTH_BASIC_SRCS=src/http/modules/ngx_http_auth_basic_module.c
+HTTP_AUTH_REQUEST_MODULE=ngx_http_auth_request_module
+HTTP_AUTH_REQUEST_SRCS=src/http/modules/ngx_http_auth_request_module.c
+
+
HTTP_AUTOINDEX_MODULE=ngx_http_autoindex_module
HTTP_AUTOINDEX_SRCS=src/http/modules/ngx_http_autoindex_module.c
diff --git a/usr.sbin/nginx/auto/types/sizeof b/usr.sbin/nginx/auto/types/sizeof
index e1d405c6500..9215a545fc4 100644
--- a/usr.sbin/nginx/auto/types/sizeof
+++ b/usr.sbin/nginx/auto/types/sizeof
@@ -45,7 +45,7 @@ if [ -x $NGX_AUTOTEST ]; then
fi
-rm -f $NGX_AUTOTEST
+rm -rf $NGX_AUTOTEST*
case $ngx_size in
diff --git a/usr.sbin/nginx/auto/types/typedef b/usr.sbin/nginx/auto/types/typedef
index d81229331fd..8b5c3689ced 100644
--- a/usr.sbin/nginx/auto/types/typedef
+++ b/usr.sbin/nginx/auto/types/typedef
@@ -49,7 +49,7 @@ END
fi
fi
- rm -f $NGX_AUTOTEST
+ rm -rf $NGX_AUTOTEST*
if [ $ngx_found = no ]; then
echo $ngx_n " $ngx_try not found$ngx_c"
diff --git a/usr.sbin/nginx/auto/types/uintptr_t b/usr.sbin/nginx/auto/types/uintptr_t
index 2f19080352b..f3cdccb2274 100644
--- a/usr.sbin/nginx/auto/types/uintptr_t
+++ b/usr.sbin/nginx/auto/types/uintptr_t
@@ -33,7 +33,7 @@ else
echo $ngx_n " uintptr_t not found" $ngx_c
fi
-rm $NGX_AUTOTEST*
+rm -rf $NGX_AUTOTEST*
if [ $found = no ]; then
diff --git a/usr.sbin/nginx/auto/unix b/usr.sbin/nginx/auto/unix
index cd4209e7b2f..10fd3d29334 100755
--- a/usr.sbin/nginx/auto/unix
+++ b/usr.sbin/nginx/auto/unix
@@ -330,7 +330,7 @@ ngx_feature_test="setsockopt(0, IPPROTO_TCP, TCP_DEFER_ACCEPT, NULL, 0)"
. auto/feature
-ngx_feature="TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_KEEPCNT"
+ngx_feature="TCP_KEEPIDLE"
ngx_feature_name="NGX_HAVE_KEEPALIVE_TUNABLE"
ngx_feature_run=no
ngx_feature_incs="#include <sys/socket.h>
@@ -344,6 +344,18 @@ ngx_feature_test="setsockopt(0, IPPROTO_TCP, TCP_KEEPIDLE, NULL, 0);
. auto/feature
+ngx_feature="TCP_FASTOPEN"
+ngx_feature_name="NGX_HAVE_TCP_FASTOPEN"
+ngx_feature_run=no
+ngx_feature_incs="#include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <netinet/tcp.h>"
+ngx_feature_path=
+ngx_feature_libs=
+ngx_feature_test="setsockopt(0, IPPROTO_TCP, TCP_FASTOPEN, NULL, 0)"
+. auto/feature
+
+
ngx_feature="TCP_INFO"
ngx_feature_name="NGX_HAVE_TCP_INFO"
ngx_feature_run=no
diff --git a/usr.sbin/nginx/conf/mime.types b/usr.sbin/nginx/conf/mime.types
index 854873a1615..fb1c1b7c424 100644
--- a/usr.sbin/nginx/conf/mime.types
+++ b/usr.sbin/nginx/conf/mime.types
@@ -1,4 +1,4 @@
-# $OpenBSD: mime.types,v 1.6 2013/11/26 10:43:06 sthen Exp $
+# $OpenBSD: mime.types,v 1.7 2014/06/12 15:27:08 robert Exp $
types {
text/html html htm shtml;
@@ -6,7 +6,7 @@ types {
text/xml xml;
image/gif gif;
image/jpeg jpeg jpg;
- application/x-javascript js;
+ application/javascript js;
application/atom+xml atom;
application/rss+xml rss;
@@ -25,13 +25,17 @@ types {
image/svg+xml svg svgz;
image/webp webp;
+ application/font-woff woff;
application/java-archive jar war ear;
+ application/json json;
application/mac-binhex40 hqx;
application/msword doc;
application/pdf pdf;
application/postscript ps eps ai;
application/rtf rtf;
+ application/vnd.apple.mpegurl m3u8;
application/vnd.ms-excel xls;
+ application/vnd.ms-fontobject eot;
application/vnd.ms-powerpoint ppt;
application/vnd.wap.wmlc wmlc;
application/vnd.google-earth.kml+xml kml;
@@ -88,6 +92,7 @@ types {
audio/x-realaudio ra;
video/3gpp 3gpp 3gp;
+ video/mp2t ts;
video/mp4 mp4;
video/mpeg mpeg mpg;
video/quicktime mov;
diff --git a/usr.sbin/nginx/conf/nginx.conf b/usr.sbin/nginx/conf/nginx.conf
index d6cfc0b554b..ee8d684a47f 100644
--- a/usr.sbin/nginx/conf/nginx.conf
+++ b/usr.sbin/nginx/conf/nginx.conf
@@ -1,16 +1,14 @@
-# $OpenBSD: nginx.conf,v 1.19 2014/04/18 20:22:17 tedu Exp $
+# $OpenBSD: nginx.conf,v 1.20 2014/06/12 15:27:08 robert Exp $
# Take note of http://wiki.nginx.org/Pitfalls
#user www;
worker_processes 1;
-#syslog local5 nginx;
-
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
-#error_log syslog:notice|logs/error.log;
+#error_log syslog:server=unix:/dev/log,severity=notice;
#pid logs/nginx.pid;
@@ -30,7 +28,7 @@ http {
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
- #access_log syslog:notice|logs/access.log main;
+ #access_log syslog:server=unix:/dev/log,severity=notice main;
#tcp_nopush on;
diff --git a/usr.sbin/nginx/contrib/README b/usr.sbin/nginx/contrib/README
index 094aa52cde3..fec4b200863 100644
--- a/usr.sbin/nginx/contrib/README
+++ b/usr.sbin/nginx/contrib/README
@@ -13,3 +13,9 @@ unicode2nginx by Maxim Dounin
configuration file format.
Two generated full maps for windows-1251 and koi8-r.
+
+vim by Evan Miller
+
+ Syntax highlighting of nginx configuration for vim, to be
+ placed into ~/.vim/.
+
diff --git a/usr.sbin/nginx/src/core/nginx.c b/usr.sbin/nginx/src/core/nginx.c
index 7f0011d879f..5960fa85658 100644
--- a/usr.sbin/nginx/src/core/nginx.c
+++ b/usr.sbin/nginx/src/core/nginx.c
@@ -389,13 +389,8 @@ main(int argc, char *const *argv)
return 1;
}
- if (cycle->log->file->fd != ngx_stderr) {
-
- if (ngx_set_stderr(cycle->log->file->fd) == NGX_FILE_ERROR) {
- ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
- ngx_set_stderr_n " failed");
- return 1;
- }
+ if (ngx_log_redirect_stderr(cycle) != NGX_OK) {
+ return 1;
}
if (log->file->fd != ngx_stderr) {
diff --git a/usr.sbin/nginx/src/core/nginx.h b/usr.sbin/nginx/src/core/nginx.h
index 77c88bf5f94..0ef0f2e110f 100644
--- a/usr.sbin/nginx/src/core/nginx.h
+++ b/usr.sbin/nginx/src/core/nginx.h
@@ -9,8 +9,8 @@
#define _NGINX_H_INCLUDED_
-#define nginx_version 1004007
-#define NGINX_VERSION "1.4.7"
+#define nginx_version 1006000
+#define NGINX_VERSION "1.6.0"
#define NGINX_VER "nginx/" NGINX_VERSION
#define NGINX_VAR "NGINX"
diff --git a/usr.sbin/nginx/src/core/ngx_conf_file.c b/usr.sbin/nginx/src/core/ngx_conf_file.c
index a262672139c..f61bfcabf99 100644
--- a/usr.sbin/nginx/src/core/ngx_conf_file.c
+++ b/usr.sbin/nginx/src/core/ngx_conf_file.c
@@ -12,7 +12,6 @@
static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last);
static ngx_int_t ngx_conf_read_token(ngx_conf_t *cf);
-static ngx_int_t ngx_conf_test_full_name(ngx_str_t *name);
static void ngx_conf_flush_files(ngx_cycle_t *cycle);
@@ -225,6 +224,11 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
* "types { ... }" directive
*/
+ if (rc == NGX_CONF_BLOCK_START) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"{\"");
+ goto failed;
+ }
+
rv = (*cf->handler)(cf, NULL, cf->handler_conf);
if (rv == NGX_CONF_OK) {
continue;
@@ -796,95 +800,11 @@ ngx_conf_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ngx_int_t
ngx_conf_full_name(ngx_cycle_t *cycle, ngx_str_t *name, ngx_uint_t conf_prefix)
{
- size_t len;
- u_char *p, *n, *prefix;
- ngx_int_t rc;
-
- rc = ngx_conf_test_full_name(name);
-
- if (rc == NGX_OK) {
- return rc;
- }
-
- if (conf_prefix) {
- len = cycle->conf_prefix.len;
- prefix = cycle->conf_prefix.data;
-
- } else {
- len = cycle->prefix.len;
- prefix = cycle->prefix.data;
- }
-
-#if (NGX_WIN32)
-
- if (rc == 2) {
- len = rc;
- }
-
-#endif
-
- n = ngx_pnalloc(cycle->pool, len + name->len + 1);
- if (n == NULL) {
- return NGX_ERROR;
- }
-
- p = ngx_cpymem(n, prefix, len);
- ngx_cpystrn(p, name->data, name->len + 1);
-
- name->len += len;
- name->data = n;
-
- return NGX_OK;
-}
-
-
-static ngx_int_t
-ngx_conf_test_full_name(ngx_str_t *name)
-{
-#if (NGX_WIN32)
- u_char c0, c1;
-
- c0 = name->data[0];
-
- if (name->len < 2) {
- if (c0 == '/') {
- return 2;
- }
+ ngx_str_t *prefix;
- return NGX_DECLINED;
- }
-
- c1 = name->data[1];
-
- if (c1 == ':') {
- c0 |= 0x20;
+ prefix = conf_prefix ? &cycle->conf_prefix : &cycle->prefix;
- if ((c0 >= 'a' && c0 <= 'z')) {
- return NGX_OK;
- }
-
- return NGX_DECLINED;
- }
-
- if (c1 == '/') {
- return NGX_OK;
- }
-
- if (c0 == '/') {
- return 2;
- }
-
- return NGX_DECLINED;
-
-#else
-
- if (name->data[0] == '/') {
- return NGX_OK;
- }
-
- return NGX_DECLINED;
-
-#endif
+ return ngx_get_full_name(cycle->pool, prefix, name);
}
diff --git a/usr.sbin/nginx/src/core/ngx_conf_file.h b/usr.sbin/nginx/src/core/ngx_conf_file.h
index 237e6ecea6e..d73a6c8bf55 100644
--- a/usr.sbin/nginx/src/core/ngx_conf_file.h
+++ b/usr.sbin/nginx/src/core/ngx_conf_file.h
@@ -5,8 +5,8 @@
*/
-#ifndef _NGX_HTTP_CONF_FILE_H_INCLUDED_
-#define _NGX_HTTP_CONF_FILE_H_INCLUDED_
+#ifndef _NGX_CONF_FILE_H_INCLUDED_
+#define _NGX_CONF_FILE_H_INCLUDED_
#include <ngx_config.h>
@@ -337,4 +337,4 @@ extern ngx_uint_t ngx_max_module;
extern ngx_module_t *ngx_modules[];
-#endif /* _NGX_HTTP_CONF_FILE_H_INCLUDED_ */
+#endif /* _NGX_CONF_FILE_H_INCLUDED_ */
diff --git a/usr.sbin/nginx/src/core/ngx_config.h b/usr.sbin/nginx/src/core/ngx_config.h
index b0cb17fca80..1da71f8d1a1 100644
--- a/usr.sbin/nginx/src/core/ngx_config.h
+++ b/usr.sbin/nginx/src/core/ngx_config.h
@@ -80,8 +80,8 @@ typedef uintptr_t ngx_uint_t;
typedef intptr_t ngx_flag_t;
-#define NGX_INT32_LEN sizeof("-2147483648") - 1
-#define NGX_INT64_LEN sizeof("-9223372036854775808") - 1
+#define NGX_INT32_LEN (sizeof("-2147483648") - 1)
+#define NGX_INT64_LEN (sizeof("-9223372036854775808") - 1)
#if (NGX_PTR_SIZE == 4)
#define NGX_INT_T_LEN NGX_INT32_LEN
diff --git a/usr.sbin/nginx/src/core/ngx_connection.c b/usr.sbin/nginx/src/core/ngx_connection.c
index 986bf0d0208..6b6e3b3a512 100644
--- a/usr.sbin/nginx/src/core/ngx_connection.c
+++ b/usr.sbin/nginx/src/core/ngx_connection.c
@@ -41,7 +41,7 @@ ngx_create_listening(ngx_conf_t *cf, void *sockaddr, socklen_t socklen)
ls->sockaddr = sa;
ls->socklen = socklen;
- len = ngx_sock_ntop(sa, text, NGX_SOCKADDR_STRLEN, 1);
+ len = ngx_sock_ntop(sa, socklen, text, NGX_SOCKADDR_STRLEN, 1);
ls->addr_text.len = len;
switch (ls->sockaddr->sa_family) {
@@ -82,6 +82,10 @@ ngx_create_listening(ngx_conf_t *cf, void *sockaddr, socklen_t socklen)
ls->setfib = -1;
#endif
+#if (NGX_HAVE_TCP_FASTOPEN)
+ ls->fastopen = -1;
+#endif
+
return ls;
}
@@ -93,8 +97,10 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle)
ngx_uint_t i;
ngx_listening_t *ls;
socklen_t olen;
-#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
+#if (NGX_HAVE_DEFERRED_ACCEPT || NGX_HAVE_TCP_FASTOPEN)
ngx_err_t err;
+#endif
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
struct accept_filter_arg af;
#endif
#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
@@ -123,7 +129,7 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle)
#if (NGX_HAVE_INET6)
case AF_INET6:
ls[i].addr_text_max_len = NGX_INET6_ADDRSTRLEN;
- len = NGX_INET6_ADDRSTRLEN + sizeof(":65535") - 1;
+ len = NGX_INET6_ADDRSTRLEN + sizeof("[]:65535") - 1;
break;
#endif
@@ -152,7 +158,8 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle)
return NGX_ERROR;
}
- len = ngx_sock_ntop(ls[i].sockaddr, ls[i].addr_text.data, len, 1);
+ len = ngx_sock_ntop(ls[i].sockaddr, ls[i].socklen,
+ ls[i].addr_text.data, len, 1);
if (len == 0) {
return NGX_ERROR;
}
@@ -192,7 +199,9 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle)
#if (NGX_HAVE_SETFIB)
- if (getsockopt(ls[i].setfib, SOL_SOCKET, SO_SETFIB,
+ olen = sizeof(int);
+
+ if (getsockopt(ls[i].fd, SOL_SOCKET, SO_SETFIB,
(void *) &ls[i].setfib, &olen)
== -1)
{
@@ -206,6 +215,27 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle)
#endif
#endif
+#if (NGX_HAVE_TCP_FASTOPEN)
+
+ olen = sizeof(int);
+
+ if (getsockopt(ls[i].fd, IPPROTO_TCP, TCP_FASTOPEN,
+ (void *) &ls[i].fastopen, &olen)
+ == -1)
+ {
+ err = ngx_socket_errno;
+
+ if (err != NGX_EOPNOTSUPP && err != NGX_ENOPROTOOPT) {
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, err,
+ "getsockopt(TCP_FASTOPEN) %V failed, ignored",
+ &ls[i].addr_text);
+ }
+
+ ls[i].fastopen = -1;
+ }
+
+#endif
+
#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
ngx_memzero(&af, sizeof(struct accept_filter_arg));
@@ -214,7 +244,7 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle)
if (getsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER, &af, &olen)
== -1)
{
- err = ngx_errno;
+ err = ngx_socket_errno;
if (err == NGX_EINVAL) {
continue;
@@ -247,7 +277,13 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle)
if (getsockopt(ls[i].fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, &olen)
== -1)
{
- ngx_log_error(NGX_LOG_NOTICE, cycle->log, ngx_errno,
+ err = ngx_socket_errno;
+
+ if (err == NGX_EOPNOTSUPP) {
+ continue;
+ }
+
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, err,
"getsockopt(TCP_DEFER_ACCEPT) for %V failed, ignored",
&ls[i].addr_text);
continue;
@@ -296,7 +332,7 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle)
continue;
}
- if (ls[i].fd != -1) {
+ if (ls[i].fd != (ngx_socket_t) -1) {
continue;
}
@@ -311,7 +347,7 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle)
s = ngx_socket(ls[i].sockaddr->sa_family, ls[i].type, 0);
- if (s == -1) {
+ if (s == (ngx_socket_t) -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
ngx_socket_n " %V failed", &ls[i].addr_text);
return NGX_ERROR;
@@ -463,16 +499,13 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle)
void
ngx_configure_listening_sockets(ngx_cycle_t *cycle)
{
- int keepalive;
+ int value;
ngx_uint_t i;
ngx_listening_t *ls;
#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
struct accept_filter_arg af;
#endif
-#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
- int timeout;
-#endif
ls = cycle->listening.elts;
for (i = 0; i < cycle->listening.nelts; i++) {
@@ -502,39 +535,51 @@ ngx_configure_listening_sockets(ngx_cycle_t *cycle)
}
if (ls[i].keepalive) {
- keepalive = (ls[i].keepalive == 1) ? 1 : 0;
+ value = (ls[i].keepalive == 1) ? 1 : 0;
if (setsockopt(ls[i].fd, SOL_SOCKET, SO_KEEPALIVE,
- (const void *) &keepalive, sizeof(int))
+ (const void *) &value, sizeof(int))
== -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"setsockopt(SO_KEEPALIVE, %d) %V failed, ignored",
- keepalive, &ls[i].addr_text);
+ value, &ls[i].addr_text);
}
}
#if (NGX_HAVE_KEEPALIVE_TUNABLE)
if (ls[i].keepidle) {
+ value = ls[i].keepidle;
+
+#if (NGX_KEEPALIVE_FACTOR)
+ value *= NGX_KEEPALIVE_FACTOR;
+#endif
+
if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_KEEPIDLE,
- (const void *) &ls[i].keepidle, sizeof(int))
+ (const void *) &value, sizeof(int))
== -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"setsockopt(TCP_KEEPIDLE, %d) %V failed, ignored",
- ls[i].keepidle, &ls[i].addr_text);
+ value, &ls[i].addr_text);
}
}
if (ls[i].keepintvl) {
+ value = ls[i].keepintvl;
+
+#if (NGX_KEEPALIVE_FACTOR)
+ value *= NGX_KEEPALIVE_FACTOR;
+#endif
+
if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_KEEPINTVL,
- (const void *) &ls[i].keepintvl, sizeof(int))
+ (const void *) &value, sizeof(int))
== -1)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"setsockopt(TCP_KEEPINTVL, %d) %V failed, ignored",
- ls[i].keepintvl, &ls[i].addr_text);
+ value, &ls[i].addr_text);
}
}
@@ -564,6 +609,19 @@ ngx_configure_listening_sockets(ngx_cycle_t *cycle)
}
#endif
+#if (NGX_HAVE_TCP_FASTOPEN)
+ if (ls[i].fastopen != -1) {
+ if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_FASTOPEN,
+ (const void *) &ls[i].fastopen, sizeof(int))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+ "setsockopt(TCP_FASTOPEN, %d) %V failed, ignored",
+ ls[i].fastopen, &ls[i].addr_text);
+ }
+ }
+#endif
+
#if 0
if (1) {
int tcp_nodelay = 1;
@@ -603,7 +661,7 @@ ngx_configure_listening_sockets(ngx_cycle_t *cycle)
if (setsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER, NULL, 0)
== -1)
{
- ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"setsockopt(SO_ACCEPTFILTER, NULL) "
"for %V failed, ignored",
&ls[i].addr_text);
@@ -630,7 +688,7 @@ ngx_configure_listening_sockets(ngx_cycle_t *cycle)
&af, sizeof(struct accept_filter_arg))
== -1)
{
- ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"setsockopt(SO_ACCEPTFILTER, \"%s\") "
"for %V failed, ignored",
ls[i].accept_filter, &ls[i].addr_text);
@@ -653,20 +711,20 @@ ngx_configure_listening_sockets(ngx_cycle_t *cycle)
* if syncookies were used), hence we use 1 second timeout
* here.
*/
- timeout = 1;
+ value = 1;
} else {
- timeout = 0;
+ value = 0;
}
if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_DEFER_ACCEPT,
- &timeout, sizeof(int))
+ &value, sizeof(int))
== -1)
{
- ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
"setsockopt(TCP_DEFER_ACCEPT, %d) for %V failed, "
"ignored",
- timeout, &ls[i].addr_text);
+ value, &ls[i].addr_text);
continue;
}
@@ -859,7 +917,7 @@ ngx_close_connection(ngx_connection_t *c)
ngx_uint_t log_error, level;
ngx_socket_t fd;
- if (c->fd == -1) {
+ if (c->fd == (ngx_socket_t) -1) {
ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed");
return;
}
@@ -1034,6 +1092,10 @@ ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s,
struct sockaddr_in6 *sin6;
#endif
+ if (c->local_socklen == 0) {
+ return NGX_ERROR;
+ }
+
switch (c->local_sockaddr->sa_family) {
#if (NGX_HAVE_INET6)
@@ -1047,6 +1109,12 @@ ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s,
break;
#endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+ case AF_UNIX:
+ addr = 1;
+ break;
+#endif
+
default: /* AF_INET */
sin = (struct sockaddr_in *) c->local_sockaddr;
addr = sin->sin_addr.s_addr;
@@ -1068,13 +1136,16 @@ ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s,
}
ngx_memcpy(c->local_sockaddr, &sa, len);
+
+ c->local_socklen = len;
}
if (s == NULL) {
return NGX_OK;
}
- s->len = ngx_sock_ntop(c->local_sockaddr, s->data, s->len, port);
+ s->len = ngx_sock_ntop(c->local_sockaddr, c->local_socklen,
+ s->data, s->len, port);
return NGX_OK;
}
diff --git a/usr.sbin/nginx/src/core/ngx_connection.h b/usr.sbin/nginx/src/core/ngx_connection.h
index 3daf2eee4cb..ed14e6023e7 100644
--- a/usr.sbin/nginx/src/core/ngx_connection.h
+++ b/usr.sbin/nginx/src/core/ngx_connection.h
@@ -80,6 +80,10 @@ struct ngx_listening_s {
int setfib;
#endif
+#if (NGX_HAVE_TCP_FASTOPEN)
+ int fastopen;
+#endif
+
};
@@ -108,6 +112,7 @@ typedef enum {
#define NGX_LOWLEVEL_BUFFERED 0x0f
#define NGX_SSL_BUFFERED 0x01
+#define NGX_SPDY_BUFFERED 0x02
struct ngx_connection_s {
@@ -134,11 +139,14 @@ struct ngx_connection_s {
socklen_t socklen;
ngx_str_t addr_text;
+ ngx_str_t proxy_protocol_addr;
+
#if (NGX_SSL)
ngx_ssl_connection_t *ssl;
#endif
struct sockaddr *local_sockaddr;
+ socklen_t local_socklen;
ngx_buf_t *buffer;
@@ -166,12 +174,15 @@ struct ngx_connection_s {
unsigned tcp_nodelay:2; /* ngx_connection_tcp_nodelay_e */
unsigned tcp_nopush:2; /* ngx_connection_tcp_nopush_e */
+ unsigned need_last_buf:1;
+
#if (NGX_HAVE_IOCP)
unsigned accept_context_updated:1;
#endif
#if (NGX_HAVE_AIO_SENDFILE)
unsigned aio_sendfile:1;
+ unsigned busy_count:2;
ngx_buf_t *busy_sendfile;
#endif
diff --git a/usr.sbin/nginx/src/core/ngx_core.h b/usr.sbin/nginx/src/core/ngx_core.h
index dfcf2d56cf8..c479a59546d 100644
--- a/usr.sbin/nginx/src/core/ngx_core.h
+++ b/usr.sbin/nginx/src/core/ngx_core.h
@@ -77,6 +77,8 @@ typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c);
#include <ngx_open_file_cache.h>
#include <ngx_os.h>
#include <ngx_connection.h>
+#include <ngx_syslog.h>
+#include <ngx_proxy_protocol.h>
#define LF (u_char) 10
diff --git a/usr.sbin/nginx/src/core/ngx_cycle.c b/usr.sbin/nginx/src/core/ngx_cycle.c
index 0c354c65665..aa42406ffe3 100644
--- a/usr.sbin/nginx/src/core/ngx_cycle.c
+++ b/usr.sbin/nginx/src/core/ngx_cycle.c
@@ -11,7 +11,6 @@
static void ngx_destroy_cycle_pools(ngx_conf_t *conf);
-static ngx_int_t ngx_cmp_sockaddr(struct sockaddr *sa1, struct sockaddr *sa2);
static ngx_int_t ngx_init_zone_pool(ngx_cycle_t *cycle,
ngx_shm_zone_t *shm_zone);
static ngx_int_t ngx_test_lockfile(u_char *file, ngx_log_t *log);
@@ -36,8 +35,6 @@ ngx_tls_key_t ngx_core_tls_key;
static ngx_connection_t dumb;
/* STUB */
-static ngx_str_t error_log = ngx_string(NGX_ERROR_LOG_PATH);
-
ngx_cycle_t *
ngx_init_cycle(ngx_cycle_t *old_cycle)
@@ -84,13 +81,6 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
cycle->pool = pool;
cycle->log = log;
- cycle->new_log.log_level = NGX_LOG_ERR;
-#if (NGX_ENABLE_SYSLOG)
- cycle->new_log.facility = SYSLOG_FACILITY;
- cycle->new_log.facility = ERR_SYSLOG_PRIORITY;
- cycle->new_log.syslog_on = 0;
- cycle->new_log.syslog_set = 0;
-#endif
cycle->old_cycle = old_cycle;
cycle->conf_prefix.len = old_cycle->conf_prefix.len;
@@ -345,11 +335,8 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
}
- if (cycle->new_log.file == NULL) {
- cycle->new_log.file = ngx_conf_open_file(cycle, &error_log);
- if (cycle->new_log.file == NULL) {
- goto failed;
- }
+ if (ngx_log_open_default(cycle) != NGX_OK) {
+ goto failed;
}
/* open the new files */
@@ -506,13 +493,15 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
continue;
}
- if (ngx_cmp_sockaddr(nls[n].sockaddr, ls[i].sockaddr) == NGX_OK)
+ if (ngx_cmp_sockaddr(nls[n].sockaddr, nls[n].socklen,
+ ls[i].sockaddr, ls[i].socklen, 1)
+ == NGX_OK)
{
nls[n].fd = ls[i].fd;
nls[n].previous = &ls[i];
ls[i].remain = 1;
- if (ls[n].backlog != nls[i].backlog) {
+ if (ls[i].backlog != nls[n].backlog) {
nls[n].listen = 1;
}
@@ -543,7 +532,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
- if (ls[n].deferred_accept && !nls[n].deferred_accept) {
+ if (ls[i].deferred_accept && !nls[n].deferred_accept) {
nls[n].delete_deferred = 1;
} else if (ls[i].deferred_accept != nls[n].deferred_accept)
@@ -555,8 +544,18 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
}
}
- if (nls[n].fd == -1) {
+ if (nls[n].fd == (ngx_socket_t) -1) {
nls[n].open = 1;
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
+ if (nls[n].accept_filter) {
+ nls[n].add_deferred = 1;
+ }
+#endif
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
+ if (nls[n].deferred_accept) {
+ nls[n].add_deferred = 1;
+ }
+#endif
}
}
@@ -588,12 +587,8 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
/* commit the new cycle configuration */
- if (!ngx_use_stderr && cycle->log->file->fd != ngx_stderr) {
-
- if (ngx_set_stderr(cycle->log->file->fd) == NGX_FILE_ERROR) {
- ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
- ngx_set_stderr_n " failed");
- }
+ if (!ngx_use_stderr) {
+ (void) ngx_log_redirect_stderr(cycle);
}
pool->log = cycle->log;
@@ -665,7 +660,7 @@ old_shm_zone_done:
ls = old_cycle->listening.elts;
for (i = 0; i < old_cycle->listening.nelts; i++) {
- if (ls[i].remain || ls[i].fd == -1) {
+ if (ls[i].remain || ls[i].fd == (ngx_socket_t) -1) {
continue;
}
@@ -829,7 +824,7 @@ failed:
ls = cycle->listening.elts;
for (i = 0; i < cycle->listening.nelts; i++) {
- if (ls[i].fd == -1 || !ls[i].open) {
+ if (ls[i].fd == (ngx_socket_t) -1 || !ls[i].open) {
continue;
}
@@ -855,74 +850,6 @@ ngx_destroy_cycle_pools(ngx_conf_t *conf)
static ngx_int_t
-ngx_cmp_sockaddr(struct sockaddr *sa1, struct sockaddr *sa2)
-{
- struct sockaddr_in *sin1, *sin2;
-#if (NGX_HAVE_INET6)
- struct sockaddr_in6 *sin61, *sin62;
-#endif
-#if (NGX_HAVE_UNIX_DOMAIN)
- struct sockaddr_un *saun1, *saun2;
-#endif
-
- if (sa1->sa_family != sa2->sa_family) {
- return NGX_DECLINED;
- }
-
- switch (sa1->sa_family) {
-
-#if (NGX_HAVE_INET6)
- case AF_INET6:
- sin61 = (struct sockaddr_in6 *) sa1;
- sin62 = (struct sockaddr_in6 *) sa2;
-
- if (sin61->sin6_port != sin62->sin6_port) {
- return NGX_DECLINED;
- }
-
- if (ngx_memcmp(&sin61->sin6_addr, &sin62->sin6_addr, 16) != 0) {
- return NGX_DECLINED;
- }
-
- break;
-#endif
-
-#if (NGX_HAVE_UNIX_DOMAIN)
- case AF_UNIX:
- saun1 = (struct sockaddr_un *) sa1;
- saun2 = (struct sockaddr_un *) sa2;
-
- if (ngx_memcmp(&saun1->sun_path, &saun2->sun_path,
- sizeof(saun1->sun_path))
- != 0)
- {
- return NGX_DECLINED;
- }
-
- break;
-#endif
-
- default: /* AF_INET */
-
- sin1 = (struct sockaddr_in *) sa1;
- sin2 = (struct sockaddr_in *) sa2;
-
- if (sin1->sin_port != sin2->sin_port) {
- return NGX_DECLINED;
- }
-
- if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) {
- return NGX_DECLINED;
- }
-
- break;
- }
-
- return NGX_OK;
-}
-
-
-static ngx_int_t
ngx_init_zone_pool(ngx_cycle_t *cycle, ngx_shm_zone_t *zn)
{
u_char *file;
@@ -1238,16 +1165,7 @@ ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user)
file[i].fd = fd;
}
-#if !(NGX_WIN32)
-
- if (cycle->log->file->fd != STDERR_FILENO) {
- if (dup2(cycle->log->file->fd, STDERR_FILENO) == -1) {
- ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
- "dup2(STDERR) failed");
- }
- }
-
-#endif
+ (void) ngx_log_redirect_stderr(cycle);
}
diff --git a/usr.sbin/nginx/src/core/ngx_cycle.h b/usr.sbin/nginx/src/core/ngx_cycle.h
index 2e4bc4ba278..21bf5ca3f25 100644
--- a/usr.sbin/nginx/src/core/ngx_cycle.h
+++ b/usr.sbin/nginx/src/core/ngx_cycle.h
@@ -41,6 +41,8 @@ struct ngx_cycle_s {
ngx_log_t *log;
ngx_log_t new_log;
+ ngx_uint_t log_use_stderr; /* unsigned log_use_stderr:1; */
+
ngx_connection_t **files;
ngx_connection_t *free_connections;
ngx_uint_t free_connection_n;
diff --git a/usr.sbin/nginx/src/core/ngx_file.c b/usr.sbin/nginx/src/core/ngx_file.c
index ce09bb6021f..4bbdc940211 100644
--- a/usr.sbin/nginx/src/core/ngx_file.c
+++ b/usr.sbin/nginx/src/core/ngx_file.c
@@ -9,11 +9,102 @@
#include <ngx_core.h>
+static ngx_int_t ngx_test_full_name(ngx_str_t *name);
+
+
static ngx_atomic_t temp_number = 0;
ngx_atomic_t *ngx_temp_number = &temp_number;
ngx_atomic_int_t ngx_random_number = 123456;
+ngx_int_t
+ngx_get_full_name(ngx_pool_t *pool, ngx_str_t *prefix, ngx_str_t *name)
+{
+ size_t len;
+ u_char *p, *n;
+ ngx_int_t rc;
+
+ rc = ngx_test_full_name(name);
+
+ if (rc == NGX_OK) {
+ return rc;
+ }
+
+ len = prefix->len;
+
+#if (NGX_WIN32)
+
+ if (rc == 2) {
+ len = rc;
+ }
+
+#endif
+
+ n = ngx_pnalloc(pool, len + name->len + 1);
+ if (n == NULL) {
+ return NGX_ERROR;
+ }
+
+ p = ngx_cpymem(n, prefix->data, len);
+ ngx_cpystrn(p, name->data, name->len + 1);
+
+ name->len += len;
+ name->data = n;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_test_full_name(ngx_str_t *name)
+{
+#if (NGX_WIN32)
+ u_char c0, c1;
+
+ c0 = name->data[0];
+
+ if (name->len < 2) {
+ if (c0 == '/') {
+ return 2;
+ }
+
+ return NGX_DECLINED;
+ }
+
+ c1 = name->data[1];
+
+ if (c1 == ':') {
+ c0 |= 0x20;
+
+ if ((c0 >= 'a' && c0 <= 'z')) {
+ return NGX_OK;
+ }
+
+ return NGX_DECLINED;
+ }
+
+ if (c1 == '/') {
+ return NGX_OK;
+ }
+
+ if (c0 == '/') {
+ return 2;
+ }
+
+ return NGX_DECLINED;
+
+#else
+
+ if (name->data[0] == '/') {
+ return NGX_OK;
+ }
+
+ return NGX_DECLINED;
+
+#endif
+}
+
+
ssize_t
ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain)
{
@@ -268,9 +359,6 @@ ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return NULL;
}
- path->len = 0;
- path->manager = NULL;
- path->loader = NULL;
path->conf_file = cf->conf_file->file.name.data;
path->line = cf->conf_file->line;
@@ -311,7 +399,7 @@ ngx_conf_merge_path_value(ngx_conf_t *cf, ngx_path_t **path, ngx_path_t *prev,
return NGX_CONF_OK;
}
- *path = ngx_palloc(cf->pool, sizeof(ngx_path_t));
+ *path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t));
if (*path == NULL) {
return NGX_CONF_ERROR;
}
@@ -330,10 +418,6 @@ ngx_conf_merge_path_value(ngx_conf_t *cf, ngx_path_t **path, ngx_path_t *prev,
+ init->level[1] + (init->level[1] ? 1 : 0)
+ init->level[2] + (init->level[2] ? 1 : 0);
- (*path)->manager = NULL;
- (*path)->loader = NULL;
- (*path)->conf_file = NULL;
-
if (ngx_add_path(cf, path) != NGX_OK) {
return NGX_CONF_ERROR;
}
@@ -417,6 +501,14 @@ ngx_add_path(ngx_conf_t *cf, ngx_path_t **slot)
if (p[i]->name.len == path->name.len
&& ngx_strcmp(p[i]->name.data, path->name.data) == 0)
{
+ if (p[i]->data != path->data) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "the same path name \"%V\" "
+ "used in %s:%ui and",
+ &p[i]->name, p[i]->conf_file, p[i]->line);
+ return NGX_ERROR;
+ }
+
for (n = 0; n < 3; n++) {
if (p[i]->level[n] != path->level[n]) {
if (path->conf_file == NULL) {
diff --git a/usr.sbin/nginx/src/core/ngx_file.h b/usr.sbin/nginx/src/core/ngx_file.h
index 18abf142316..3ea6c28c863 100644
--- a/usr.sbin/nginx/src/core/ngx_file.h
+++ b/usr.sbin/nginx/src/core/ngx_file.h
@@ -122,6 +122,9 @@ struct ngx_tree_ctx_s {
};
+ngx_int_t ngx_get_full_name(ngx_pool_t *pool, ngx_str_t *prefix,
+ ngx_str_t *name);
+
ssize_t ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain);
ngx_int_t ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path,
ngx_pool_t *pool, ngx_uint_t persistent, ngx_uint_t clean,
diff --git a/usr.sbin/nginx/src/core/ngx_hash.c b/usr.sbin/nginx/src/core/ngx_hash.c
index b532945027c..c7bfed70979 100644
--- a/usr.sbin/nginx/src/core/ngx_hash.c
+++ b/usr.sbin/nginx/src/core/ngx_hash.c
@@ -282,7 +282,7 @@ ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts)
start = hinit->max_size - 1000;
}
- for (size = start; size < hinit->max_size; size++) {
+ for (size = start; size <= hinit->max_size; size++) {
ngx_memzero(test, size * sizeof(u_short));
@@ -312,15 +312,12 @@ ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts)
continue;
}
- ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
- "could not build the %s, you should increase "
- "either %s_max_size: %i or %s_bucket_size: %i",
+ ngx_log_error(NGX_LOG_WARN, hinit->pool->log, 0,
+ "could not build optimal %s, you should increase "
+ "either %s_max_size: %i or %s_bucket_size: %i; "
+ "ignoring %s_bucket_size",
hinit->name, hinit->name, hinit->max_size,
- hinit->name, hinit->bucket_size);
-
- ngx_free(test);
-
- return NGX_ERROR;
+ hinit->name, hinit->bucket_size, hinit->name);
found:
diff --git a/usr.sbin/nginx/src/core/ngx_inet.c b/usr.sbin/nginx/src/core/ngx_inet.c
index 7757ab7d905..26c5bc4b0bb 100644
--- a/usr.sbin/nginx/src/core/ngx_inet.c
+++ b/usr.sbin/nginx/src/core/ngx_inet.c
@@ -174,7 +174,8 @@ ngx_inet6_addr(u_char *p, size_t len, u_char *addr)
size_t
-ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len, ngx_uint_t port)
+ngx_sock_ntop(struct sockaddr *sa, socklen_t socklen, u_char *text, size_t len,
+ ngx_uint_t port)
{
u_char *p;
struct sockaddr_in *sin;
@@ -230,9 +231,18 @@ ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len, ngx_uint_t port)
case AF_UNIX:
saun = (struct sockaddr_un *) sa;
+ /* on Linux sockaddr might not include sun_path at all */
+
+ if (socklen <= (socklen_t) offsetof(struct sockaddr_un, sun_path)) {
+ p = ngx_snprintf(text, len, "unix:%Z");
+
+ } else {
+ p = ngx_snprintf(text, len, "unix:%s%Z", saun->sun_path);
+ }
+
/* we do not include trailing zero in address length */
- return ngx_snprintf(text, len, "unix:%s%Z", saun->sun_path) - text - 1;
+ return (p - text - 1);
#endif
@@ -953,6 +963,9 @@ ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u)
ngx_memzero(&hints, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
+#ifdef AI_ADDRCONFIG
+ hints.ai_flags = AI_ADDRCONFIG;
+#endif
if (getaddrinfo((char *) host, NULL, &hints, &res) != 0) {
u->err = "host not found";
@@ -1020,7 +1033,7 @@ ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u)
goto failed;
}
- len = ngx_sock_ntop((struct sockaddr *) sin, p, len, 1);
+ len = ngx_sock_ntop((struct sockaddr *) sin, rp->ai_addrlen, p, len, 1);
u->addrs[i].name.len = len;
u->addrs[i].name.data = p;
@@ -1053,7 +1066,8 @@ ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u)
goto failed;
}
- len = ngx_sock_ntop((struct sockaddr *) sin6, p, len, 1);
+ len = ngx_sock_ntop((struct sockaddr *) sin6, rp->ai_addrlen, p,
+ len, 1);
u->addrs[i].name.len = len;
u->addrs[i].name.data = p;
@@ -1138,7 +1152,8 @@ ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u)
return NGX_ERROR;
}
- len = ngx_sock_ntop((struct sockaddr *) sin, p, len, 1);
+ len = ngx_sock_ntop((struct sockaddr *) sin,
+ sizeof(struct sockaddr_in), p, len, 1);
u->addrs[i].name.len = len;
u->addrs[i].name.data = p;
@@ -1181,3 +1196,76 @@ ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u)
}
#endif /* NGX_HAVE_GETADDRINFO && NGX_HAVE_INET6 */
+
+
+ngx_int_t
+ngx_cmp_sockaddr(struct sockaddr *sa1, socklen_t slen1,
+ struct sockaddr *sa2, socklen_t slen2, ngx_uint_t cmp_port)
+{
+ struct sockaddr_in *sin1, *sin2;
+#if (NGX_HAVE_INET6)
+ struct sockaddr_in6 *sin61, *sin62;
+#endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+ struct sockaddr_un *saun1, *saun2;
+#endif
+
+ if (sa1->sa_family != sa2->sa_family) {
+ return NGX_DECLINED;
+ }
+
+ switch (sa1->sa_family) {
+
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+
+ sin61 = (struct sockaddr_in6 *) sa1;
+ sin62 = (struct sockaddr_in6 *) sa2;
+
+ if (cmp_port && sin61->sin6_port != sin62->sin6_port) {
+ return NGX_DECLINED;
+ }
+
+ if (ngx_memcmp(&sin61->sin6_addr, &sin62->sin6_addr, 16) != 0) {
+ return NGX_DECLINED;
+ }
+
+ break;
+#endif
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+ case AF_UNIX:
+
+ /* TODO length */
+
+ saun1 = (struct sockaddr_un *) sa1;
+ saun2 = (struct sockaddr_un *) sa2;
+
+ if (ngx_memcmp(&saun1->sun_path, &saun2->sun_path,
+ sizeof(saun1->sun_path))
+ != 0)
+ {
+ return NGX_DECLINED;
+ }
+
+ break;
+#endif
+
+ default: /* AF_INET */
+
+ sin1 = (struct sockaddr_in *) sa1;
+ sin2 = (struct sockaddr_in *) sa2;
+
+ if (cmp_port && sin1->sin_port != sin2->sin_port) {
+ return NGX_DECLINED;
+ }
+
+ if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) {
+ return NGX_DECLINED;
+ }
+
+ break;
+ }
+
+ return NGX_OK;
+}
diff --git a/usr.sbin/nginx/src/core/ngx_inet.h b/usr.sbin/nginx/src/core/ngx_inet.h
index 6a5a3687d8c..05557509d65 100644
--- a/usr.sbin/nginx/src/core/ngx_inet.h
+++ b/usr.sbin/nginx/src/core/ngx_inet.h
@@ -107,14 +107,16 @@ in_addr_t ngx_inet_addr(u_char *text, size_t len);
ngx_int_t ngx_inet6_addr(u_char *p, size_t len, u_char *addr);
size_t ngx_inet6_ntop(u_char *p, u_char *text, size_t len);
#endif
-size_t ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len,
- ngx_uint_t port);
+size_t ngx_sock_ntop(struct sockaddr *sa, socklen_t socklen, u_char *text,
+ size_t len, ngx_uint_t port);
size_t ngx_inet_ntop(int family, void *addr, u_char *text, size_t len);
ngx_int_t ngx_ptocidr(ngx_str_t *text, ngx_cidr_t *cidr);
ngx_int_t ngx_parse_addr(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text,
size_t len);
ngx_int_t ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u);
ngx_int_t ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u);
+ngx_int_t ngx_cmp_sockaddr(struct sockaddr *sa1, socklen_t slen1,
+ struct sockaddr *sa2, socklen_t slen2, ngx_uint_t cmp_port);
#endif /* _NGX_INET_H_INCLUDED_ */
diff --git a/usr.sbin/nginx/src/core/ngx_list.c b/usr.sbin/nginx/src/core/ngx_list.c
index 89ea8235275..d0eb15930a8 100644
--- a/usr.sbin/nginx/src/core/ngx_list.c
+++ b/usr.sbin/nginx/src/core/ngx_list.c
@@ -19,18 +19,10 @@ ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size)
return NULL;
}
- list->part.elts = ngx_palloc(pool, n * size);
- if (list->part.elts == NULL) {
+ if (ngx_list_init(list, pool, n, size) != NGX_OK) {
return NULL;
}
- list->part.nelts = 0;
- list->part.next = NULL;
- list->last = &list->part;
- list->size = size;
- list->nalloc = n;
- list->pool = pool;
-
return list;
}
diff --git a/usr.sbin/nginx/src/core/ngx_log.c b/usr.sbin/nginx/src/core/ngx_log.c
index ddc2bbf6847..375d52f65d4 100644
--- a/usr.sbin/nginx/src/core/ngx_log.c
+++ b/usr.sbin/nginx/src/core/ngx_log.c
@@ -10,15 +10,8 @@
static char *ngx_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
-#if (NGX_ENABLE_SYSLOG)
-static char *ngx_set_syslog(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
-void log_exit(ngx_cycle_t *cycle);
-
-typedef struct{
- ngx_str_t name;
- ngx_int_t macro;
-} ngx_string_to_macro_t;
-#endif
+static char *ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log);
+static void ngx_log_insert(ngx_log_t *log, ngx_log_t *new_log);
static ngx_command_t ngx_errlog_commands[] = {
@@ -30,15 +23,6 @@ static ngx_command_t ngx_errlog_commands[] = {
0,
NULL},
-#if (NGX_ENABLE_SYSLOG)
- {ngx_string("syslog"),
- NGX_MAIN_CONF|NGX_CONF_TAKE12,
- ngx_set_syslog,
- 0,
- 0,
- NULL},
-#endif
-
ngx_null_command
};
@@ -61,11 +45,7 @@ ngx_module_t ngx_errlog_module = {
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
-#if (NGX_ENABLE_SYSLOG)
- log_exit, /* exit master */
-#else
- NULL,
-#endif
+ NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
@@ -74,48 +54,6 @@ static ngx_log_t ngx_log;
static ngx_open_file_t ngx_log_file;
ngx_uint_t ngx_use_stderr = 1;
-#if (NGX_ENABLE_SYSLOG)
-static ngx_string_to_macro_t ngx_syslog_facilities[] = {
- {ngx_string("auth"), LOG_AUTH},
-#if !(NGX_SOLARIS)
- {ngx_string("authpriv"), LOG_AUTHPRIV},
-#endif
- {ngx_string("cron"), LOG_CRON},
- {ngx_string("daemon"), LOG_DAEMON},
-#if !(NGX_SOLARIS)
- {ngx_string("ftp"), LOG_FTP},
-#endif
- {ngx_string("kern"), LOG_KERN},
- {ngx_string("local0"), LOG_LOCAL0},
- {ngx_string("local1"), LOG_LOCAL1},
- {ngx_string("local2"), LOG_LOCAL2},
- {ngx_string("local3"), LOG_LOCAL3},
- {ngx_string("local4"), LOG_LOCAL4},
- {ngx_string("local5"), LOG_LOCAL5},
- {ngx_string("local6"), LOG_LOCAL6},
- {ngx_string("local7"), LOG_LOCAL7},
- {ngx_string("lpr"), LOG_LPR},
- {ngx_string("mail"), LOG_MAIL},
- {ngx_string("news"), LOG_NEWS},
- {ngx_string("syslog"), LOG_SYSLOG},
- {ngx_string("user"), LOG_USER},
- {ngx_string("uucp"), LOG_UUCP},
- { ngx_null_string, 0}
-};
-
-static ngx_string_to_macro_t ngx_syslog_priorities[] = {
- {ngx_string("emerg"), LOG_EMERG},
- {ngx_string("alert"), LOG_ALERT},
- {ngx_string("crit"), LOG_CRIT},
- {ngx_string("error"), LOG_ERR},
- {ngx_string("err"), LOG_ERR},
- {ngx_string("warn"), LOG_WARNING},
- {ngx_string("notice"),LOG_NOTICE},
- {ngx_string("info"), LOG_INFO},
- {ngx_string("debug"), LOG_DEBUG},
- { ngx_null_string, 0}
-};
-#endif
static ngx_str_t err_levels[] = {
ngx_null_string,
@@ -150,19 +88,11 @@ ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
#endif
{
#if (NGX_HAVE_VARIADIC_MACROS)
- va_list args;
-#endif
- u_char *p, *last, *msg;
-#if (NGX_ENABLE_SYSLOG)
- u_char *errstr_syslog;
-#endif
- u_char errstr[NGX_MAX_ERROR_STR];
-
-#if !(NGX_ENABLE_SYSLOG)
- if (log->file->fd == NGX_INVALID_FILE) {
- return;
- }
+ va_list args;
#endif
+ u_char *p, *last, *msg;
+ u_char errstr[NGX_MAX_ERROR_STR];
+ ngx_uint_t wrote_stderr, debug_connection;
last = errstr + NGX_MAX_ERROR_STR;
@@ -171,10 +101,6 @@ ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
p = errstr + ngx_cached_err_log_time.len;
-#if (NGX_ENABLE_SYSLOG)
- errstr_syslog = p;
-#endif
-
p = ngx_slprintf(p, last, " [%V] ", &err_levels[level]);
/* pid#tid */
@@ -213,27 +139,33 @@ ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
ngx_linefeed(p);
-#if (NGX_ENABLE_SYSLOG)
- if (log->file != NULL && log->file->name.len != 0) {
- (void) ngx_write_fd(log->file->fd, errstr, p - errstr);
- }
+ wrote_stderr = 0;
+ debug_connection = (log->log_level & NGX_LOG_DEBUG_CONNECTION) != 0;
+
+ while (log) {
+
+ if (log->log_level < level && !debug_connection) {
+ break;
+ }
+
+ if (log->writer) {
+ log->writer(log, level, errstr, p - errstr);
+ log = log->next;
+ continue;
+ }
+
+ (void) ngx_write_fd(log->file->fd, errstr, p - errstr);
- /* Don't send the debug level info to syslog */
- if (log->syslog_on && level < NGX_LOG_DEBUG) {
- /* write to syslog */
- syslog(log->priority, "%.*s", (int)(p - errstr_syslog), errstr_syslog);
+ if (log->file->fd == ngx_stderr) {
+ wrote_stderr = 1;
+ }
+
+ log = log->next;
}
-#else
- (void) ngx_write_fd(log->file->fd, errstr, p - errstr);
-#endif
if (!ngx_use_stderr
|| level > NGX_LOG_WARN
-#if (NGX_ENABLE_SYSLOG)
- || (log->file != NULL && log->file->fd == ngx_stderr))
-#else
- || log->file->fd == ngx_stderr)
-#endif
+ || wrote_stderr)
{
return;
}
@@ -437,75 +369,93 @@ ngx_log_init(u_char *prefix)
}
-ngx_log_t *
-ngx_log_create(ngx_cycle_t *cycle, ngx_str_t *name)
+ngx_int_t
+ngx_log_open_default(ngx_cycle_t *cycle)
{
- ngx_log_t *log;
+ ngx_log_t *log;
+ static ngx_str_t error_log = ngx_string(NGX_ERROR_LOG_PATH);
+
+ if (ngx_log_get_file_log(&cycle->new_log) != NULL) {
+ return NGX_OK;
+ }
+
+ if (cycle->new_log.log_level != 0) {
+ /* there are some error logs, but no files */
- log = ngx_pcalloc(cycle->pool, sizeof(ngx_log_t));
- if (log == NULL) {
- return NULL;
+ log = ngx_pcalloc(cycle->pool, sizeof(ngx_log_t));
+ if (log == NULL) {
+ return NGX_ERROR;
+ }
+
+ log->log_level = NGX_LOG_ERR;
+ ngx_log_insert(&cycle->new_log, log);
+
+ } else {
+ /* no error logs at all */
+ log = &cycle->new_log;
+ log->log_level = NGX_LOG_ERR;
}
- log->file = ngx_conf_open_file(cycle, name);
+ log->file = ngx_conf_open_file(cycle, &error_log);
if (log->file == NULL) {
- return NULL;
+ return NGX_ERROR;
}
- return log;
+ return NGX_OK;
}
-#if (NGX_ENABLE_SYSLOG)
ngx_int_t
-ngx_log_get_priority(ngx_conf_t *cf, ngx_str_t *priority)
+ngx_log_redirect_stderr(ngx_cycle_t *cycle)
{
- ngx_int_t p = 0;
- ngx_uint_t n, match = 0;
-
- for (n = 0; ngx_syslog_priorities[n].name.len != 0; n++) {
- if (ngx_strncmp(priority->data, ngx_syslog_priorities[n].name.data,
- ngx_syslog_priorities[n].name.len) == 0) {
- p = ngx_syslog_priorities[n].macro;
- match = 1;
- }
+ ngx_fd_t fd;
+
+ if (cycle->log_use_stderr) {
+ return NGX_OK;
}
- if (!match) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "invalid syslog priority \"%V\"", priority);
- return -1;
+ /* file log always exists when we are called */
+ fd = ngx_log_get_file_log(cycle->log)->file->fd;
+
+ if (fd != ngx_stderr) {
+ if (ngx_set_stderr(fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ ngx_set_stderr_n " failed");
+
+ return NGX_ERROR;
+ }
}
- return p;
+ return NGX_OK;
}
-char *
-ngx_log_set_priority(ngx_conf_t *cf, ngx_str_t *priority, ngx_log_t *log)
+ngx_log_t *
+ngx_log_get_file_log(ngx_log_t *head)
{
- log->priority = ERR_SYSLOG_PRIORITY;
-
- if (priority->len == 0) {
- return NGX_CONF_OK;
- }
+ ngx_log_t *log;
- log->priority = ngx_log_get_priority(cf, priority);
- if (log->priority == (-1)) {
- return NGX_CONF_ERROR;
+ for (log = head; log; log = log->next) {
+ if (log->file != NULL) {
+ return log;
+ }
}
- return NGX_CONF_OK;
+ return NULL;
}
-#endif
-char *
+static char *
ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log)
{
ngx_uint_t i, n, d, found;
ngx_str_t *value;
+ if (cf->args->nelts == 2) {
+ log->log_level = NGX_LOG_ERR;
+ return NGX_CONF_OK;
+ }
+
value = cf->args->elts;
for (i = 2; i < cf->args->nelts; i++) {
@@ -561,136 +511,109 @@ ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log)
static char *
ngx_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
- ngx_str_t *value, name;
-#if (NGX_ENABLE_SYSLOG)
- u_char *off = NULL;
- ngx_str_t priority;
+ ngx_log_t *dummy;
- ngx_str_null(&name);
- ngx_str_null(&priority);
-#endif
+ dummy = &cf->cycle->new_log;
- if (cf->cycle->new_log.file) {
- return "is duplicate";
- }
+ return ngx_log_set_log(cf, &dummy);
+}
- value = cf->args->elts;
-#if (NGX_ENABLE_SYSLOG)
- if (ngx_strncmp(value[1].data, "syslog", sizeof("syslog") - 1) == 0) {
- if (!cf->cycle->new_log.syslog_set) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "You must set the syslog directive and enable it first.");
+char *
+ngx_log_set_log(ngx_conf_t *cf, ngx_log_t **head)
+{
+ ngx_log_t *new_log;
+ ngx_str_t *value, name;
+ ngx_syslog_peer_t *peer;
+
+ if (*head != NULL && (*head)->log_level == 0) {
+ new_log = *head;
+
+ } else {
+
+ new_log = ngx_pcalloc(cf->pool, sizeof(ngx_log_t));
+ if (new_log == NULL) {
return NGX_CONF_ERROR;
}
- cf->cycle->new_log.syslog_on = 1;
+ if (*head == NULL) {
+ *head = new_log;
+ }
+ }
- if (value[1].data[sizeof("syslog") - 1] == ':') {
- priority.len = value[1].len - sizeof("syslog");
- priority.data = value[1].data + sizeof("syslog");
+ value = cf->args->elts;
- off = (u_char *)ngx_strchr(priority.data, (int) '|');
- if (off != NULL) {
- priority.len = off - priority.data;
+ if (ngx_strcmp(value[1].data, "stderr") == 0) {
+ ngx_str_null(&name);
+ cf->cycle->log_use_stderr = 1;
- off++;
- name.len = value[1].data + value[1].len - off;
- name.data = off;
- }
+ new_log->file = ngx_conf_open_file(cf->cycle, &name);
+ if (new_log->file == NULL) {
+ return NGX_CONF_ERROR;
}
- else {
- if (value[1].len > sizeof("syslog")) {
- name.len = value[1].len - sizeof("syslog");
- name.data = value[1].data + sizeof("syslog");
- }
+
+
+ } else if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) {
+ peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t));
+ if (peer == NULL) {
+ return NGX_CONF_ERROR;
}
- if (ngx_log_set_priority(cf, &priority, &cf->cycle->new_log) == NGX_CONF_ERROR) {
+ if (ngx_syslog_process_conf(cf, peer) != NGX_CONF_OK) {
return NGX_CONF_ERROR;
}
- }
- else if (ngx_strcmp(value[1].data, "stderr") == 0) {
-#else
- if (ngx_strcmp(value[1].data, "stderr") == 0) {
-#endif
- ngx_str_null(&name);
+
+ new_log->writer = ngx_syslog_writer;
+ new_log->wdata = peer;
} else {
- name = value[1];
+ new_log->file = ngx_conf_open_file(cf->cycle, &value[1]);
+ if (new_log->file == NULL) {
+ return NGX_CONF_ERROR;
+ }
}
- cf->cycle->new_log.file = ngx_conf_open_file(cf->cycle, &name);
- if (cf->cycle->new_log.file == NULL) {
- return NULL;
+ if (ngx_log_set_levels(cf, new_log) != NGX_CONF_OK) {
+ return NGX_CONF_ERROR;
}
- if (cf->args->nelts == 2) {
- cf->cycle->new_log.log_level = NGX_LOG_ERR;
- return NGX_CONF_OK;
+ if (*head != new_log) {
+ ngx_log_insert(*head, new_log);
}
- cf->cycle->new_log.log_level = 0;
-
- return ngx_log_set_levels(cf, &cf->cycle->new_log);
+ return NGX_CONF_OK;
}
-#if (NGX_ENABLE_SYSLOG)
-
-#define SYSLOG_IDENT_NAME "nginx"
-
-static char *
-ngx_set_syslog(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+static void
+ngx_log_insert(ngx_log_t *log, ngx_log_t *new_log)
{
- char *program;
- ngx_str_t *value;
- ngx_int_t facility = SYSLOG_FACILITY, match = 0;
- ngx_uint_t n;
+ ngx_log_t tmp;
- value = cf->args->elts;
+ if (new_log->log_level > log->log_level) {
- if (cf->cycle->new_log.syslog_set) {
- return "is duplicate";
- }
+ /*
+ * list head address is permanent, insert new log after
+ * head and swap its contents with head
+ */
- cf->cycle->new_log.syslog_set = 1;
+ tmp = *log;
+ *log = *new_log;
+ *new_log = tmp;
- for (n = 0; ngx_syslog_facilities[n].name.len != 0; n++) {
- if (ngx_strncmp(value[1].data, ngx_syslog_facilities[n].name.data,
- ngx_syslog_facilities[n].name.len) == 0) {
- facility = ngx_syslog_facilities[n].macro;
- match = 1;
- break;
- }
+ log->next = new_log;
+ return;
}
- if (match) {
- cf->cycle->new_log.facility = facility;
- cf->cycle->new_log.priority = ERR_SYSLOG_PRIORITY;
- }
- else {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "invalid syslog facility \"%V\"", &value[1]);
- return NGX_CONF_ERROR;
- }
+ while (log->next) {
+ if (new_log->log_level > log->next->log_level) {
+ new_log->next = log->next;
+ log->next = new_log;
+ return;
+ }
- program = SYSLOG_IDENT_NAME;
- if (cf->args->nelts > 2) {
- program = (char *) value[2].data;
+ log = log->next;
}
- openlog(program, LOG_ODELAY, facility);
-
- return NGX_CONF_OK;
+ log->next = new_log;
}
-
-
-void log_exit(ngx_cycle_t *cycle)
-{
- if (cycle->new_log.syslog_set) {
- closelog();
- }
-}
-#endif
-
diff --git a/usr.sbin/nginx/src/core/ngx_log.h b/usr.sbin/nginx/src/core/ngx_log.h
index 5e7fdbf4b4e..c1a52c44f0b 100644
--- a/usr.sbin/nginx/src/core/ngx_log.h
+++ b/usr.sbin/nginx/src/core/ngx_log.h
@@ -12,13 +12,6 @@
#include <ngx_config.h>
#include <ngx_core.h>
-#if (NGX_ENABLE_SYSLOG)
-#include <syslog.h>
-
-#define SYSLOG_FACILITY LOG_LOCAL5
-#define ERR_SYSLOG_PRIORITY LOG_ERR
-#endif
-
#define NGX_LOG_STDERR 0
#define NGX_LOG_EMERG 1
@@ -50,6 +43,8 @@
typedef u_char *(*ngx_log_handler_pt) (ngx_log_t *log, u_char *buf, size_t len);
+typedef void (*ngx_log_writer_pt) (ngx_log_t *log, ngx_uint_t level,
+ u_char *buf, size_t len);
struct ngx_log_s {
@@ -61,6 +56,9 @@ struct ngx_log_s {
ngx_log_handler_pt handler;
void *data;
+ ngx_log_writer_pt writer;
+ void *wdata;
+
/*
* we declare "action" as "char *" because the actions are usually
* the static strings and in the "u_char *" case we have to override
@@ -69,12 +67,7 @@ struct ngx_log_s {
char *action;
-#if (NGX_ENABLE_SYSLOG)
- ngx_int_t priority;
- ngx_int_t facility;
- unsigned syslog_on:1; /* unsigned :1 syslog_on */
- unsigned syslog_set:1; /*unsigned :1 syslog_set */
-#endif
+ ngx_log_t *next;
};
@@ -234,15 +227,13 @@ void ngx_cdecl ngx_log_debug_core(ngx_log_t *log, ngx_err_t err,
/*********************************/
ngx_log_t *ngx_log_init(u_char *prefix);
-ngx_log_t *ngx_log_create(ngx_cycle_t *cycle, ngx_str_t *name);
-#if (NGX_ENABLE_SYSLOG)
-ngx_int_t ngx_log_get_priority(ngx_conf_t *cf, ngx_str_t *priority);
-char * ngx_log_set_priority(ngx_conf_t *cf, ngx_str_t *priority, ngx_log_t *log);
-#endif
-char *ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log);
void ngx_cdecl ngx_log_abort(ngx_err_t err, const char *fmt, ...);
void ngx_cdecl ngx_log_stderr(ngx_err_t err, const char *fmt, ...);
u_char *ngx_log_errno(u_char *buf, u_char *last, ngx_err_t err);
+ngx_int_t ngx_log_open_default(ngx_cycle_t *cycle);
+ngx_int_t ngx_log_redirect_stderr(ngx_cycle_t *cycle);
+ngx_log_t *ngx_log_get_file_log(ngx_log_t *head);
+char *ngx_log_set_log(ngx_conf_t *cf, ngx_log_t **head);
/*
diff --git a/usr.sbin/nginx/src/core/ngx_open_file_cache.c b/usr.sbin/nginx/src/core/ngx_open_file_cache.c
index c44ac96b8b7..4df2134b2bd 100644
--- a/usr.sbin/nginx/src/core/ngx_open_file_cache.c
+++ b/usr.sbin/nginx/src/core/ngx_open_file_cache.c
@@ -25,6 +25,10 @@ static void ngx_open_file_cache_cleanup(void *data);
#if (NGX_HAVE_OPENAT)
static ngx_fd_t ngx_openat_file_owner(ngx_fd_t at_fd, const u_char *name,
ngx_int_t mode, ngx_int_t create, ngx_int_t access, ngx_log_t *log);
+#if (NGX_HAVE_O_PATH)
+static ngx_int_t ngx_file_o_path_info(ngx_fd_t fd, ngx_file_info_t *fi,
+ ngx_log_t *log);
+#endif
#endif
static ngx_fd_t ngx_open_file_wrapper(ngx_str_t *name,
ngx_open_file_info_t *of, ngx_int_t mode, ngx_int_t create,
@@ -124,7 +128,7 @@ ngx_open_file_cache_cleanup(void *data)
if (cache->current) {
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
- "%d items still leave in open file cache",
+ "%ui items still leave in open file cache",
cache->current);
}
@@ -517,10 +521,17 @@ ngx_openat_file_owner(ngx_fd_t at_fd, const u_char *name,
goto failed;
}
+#if (NGX_HAVE_O_PATH)
+ if (ngx_file_o_path_info(fd, &fi, log) == NGX_ERROR) {
+ err = ngx_errno;
+ goto failed;
+ }
+#else
if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
err = ngx_errno;
goto failed;
}
+#endif
if (fi.st_uid != atfi.st_uid) {
err = NGX_ELOOP;
@@ -541,8 +552,63 @@ failed:
return NGX_INVALID_FILE;
}
+
+#if (NGX_HAVE_O_PATH)
+
+static ngx_int_t
+ngx_file_o_path_info(ngx_fd_t fd, ngx_file_info_t *fi, ngx_log_t *log)
+{
+ static ngx_uint_t use_fstat = 1;
+
+ /*
+ * In Linux 2.6.39 the O_PATH flag was introduced that allows to obtain
+ * a descriptor without actually opening file or directory. It requires
+ * less permissions for path components, but till Linux 3.6 fstat() returns
+ * EBADF on such descriptors, and fstatat() with the AT_EMPTY_PATH flag
+ * should be used instead.
+ *
+ * Three scenarios are handled in this function:
+ *
+ * 1) The kernel is newer than 3.6 or fstat() with O_PATH support was
+ * backported by vendor. Then fstat() is used.
+ *
+ * 2) The kernel is newer than 2.6.39 but older than 3.6. In this case
+ * the first call of fstat() returns EBADF and we fallback to fstatat()
+ * with AT_EMPTY_PATH which was introduced at the same time as O_PATH.
+ *
+ * 3) The kernel is older than 2.6.39 but nginx was build with O_PATH
+ * support. Since descriptors are opened with O_PATH|O_RDONLY flags
+ * and O_PATH is ignored by the kernel then the O_RDONLY flag is
+ * actually used. In this case fstat() just works.
+ */
+
+ if (use_fstat) {
+ if (ngx_fd_info(fd, fi) != NGX_FILE_ERROR) {
+ return NGX_OK;
+ }
+
+ if (ngx_errno != NGX_EBADF) {
+ return NGX_ERROR;
+ }
+
+ ngx_log_error(NGX_LOG_NOTICE, log, 0,
+ "fstat(O_PATH) failed with EBADF, "
+ "switching to fstatat(AT_EMPTY_PATH)");
+
+ use_fstat = 0;
+ }
+
+ if (ngx_file_at_info(fd, "", fi, AT_EMPTY_PATH) != NGX_FILE_ERROR) {
+ return NGX_OK;
+ }
+
+ return NGX_ERROR;
+}
+
#endif
+#endif /* NGX_HAVE_OPENAT */
+
static ngx_fd_t
ngx_open_file_wrapper(ngx_str_t *name, ngx_open_file_info_t *of,
diff --git a/usr.sbin/nginx/src/core/ngx_palloc.c b/usr.sbin/nginx/src/core/ngx_palloc.c
index efbc24452bd..1f70f9eee29 100644
--- a/usr.sbin/nginx/src/core/ngx_palloc.c
+++ b/usr.sbin/nginx/src/core/ngx_palloc.c
@@ -105,11 +105,14 @@ ngx_reset_pool(ngx_pool_t *pool)
}
}
- pool->large = NULL;
-
for (p = pool; p; p = p->d.next) {
p->d.last = (u_char *) p + sizeof(ngx_pool_t);
+ p->d.failed = 0;
}
+
+ pool->current = pool;
+ pool->chain = NULL;
+ pool->large = NULL;
}
diff --git a/usr.sbin/nginx/src/core/ngx_proxy_protocol.c b/usr.sbin/nginx/src/core/ngx_proxy_protocol.c
new file mode 100644
index 00000000000..59ef010fc06
--- /dev/null
+++ b/usr.sbin/nginx/src/core/ngx_proxy_protocol.c
@@ -0,0 +1,91 @@
+
+/*
+ * Copyright (C) Roman Arutyunyan
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+u_char *
+ngx_proxy_protocol_parse(ngx_connection_t *c, u_char *buf, u_char *last)
+{
+ size_t len;
+ u_char ch, *p, *addr;
+
+ p = buf;
+ len = last - buf;
+
+ if (len < 8 || ngx_strncmp(p, "PROXY ", 6) != 0) {
+ goto invalid;
+ }
+
+ p += 6;
+ len -= 6;
+
+ if (len >= 7 && ngx_strncmp(p, "UNKNOWN", 7) == 0) {
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0,
+ "PROXY protocol unknown protocol");
+ p += 7;
+ goto skip;
+ }
+
+ if (len < 5 || ngx_strncmp(p, "TCP", 3) != 0
+ || (p[3] != '4' && p[3] != '6') || p[4] != ' ')
+ {
+ goto invalid;
+ }
+
+ p += 5;
+ addr = p;
+
+ for ( ;; ) {
+ if (p == last) {
+ goto invalid;
+ }
+
+ ch = *p++;
+
+ if (ch == ' ') {
+ break;
+ }
+
+ if (ch != ':' && ch != '.'
+ && (ch < 'a' || ch > 'f')
+ && (ch < 'A' || ch > 'F')
+ && (ch < '0' || ch > '9'))
+ {
+ goto invalid;
+ }
+ }
+
+ len = p - addr - 1;
+ c->proxy_protocol_addr.data = ngx_pnalloc(c->pool, len);
+
+ if (c->proxy_protocol_addr.data == NULL) {
+ return NULL;
+ }
+
+ ngx_memcpy(c->proxy_protocol_addr.data, addr, len);
+ c->proxy_protocol_addr.len = len;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
+ "PROXY protocol address: \"%V\"", &c->proxy_protocol_addr);
+
+skip:
+
+ for ( /* void */ ; p < last - 1; p++) {
+ if (p[0] == CR && p[1] == LF) {
+ return p + 2;
+ }
+ }
+
+invalid:
+
+ ngx_log_error(NGX_LOG_ERR, c->log, 0,
+ "broken header: \"%*s\"", (size_t) (last - buf), buf);
+
+ return NULL;
+}
diff --git a/usr.sbin/nginx/src/core/ngx_proxy_protocol.h b/usr.sbin/nginx/src/core/ngx_proxy_protocol.h
new file mode 100644
index 00000000000..4f3912512f1
--- /dev/null
+++ b/usr.sbin/nginx/src/core/ngx_proxy_protocol.h
@@ -0,0 +1,23 @@
+
+/*
+ * Copyright (C) Roman Arutyunyan
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_PROXY_PROTOCOL_H_INCLUDED_
+#define _NGX_PROXY_PROTOCOL_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#define NGX_PROXY_PROTOCOL_MAX_HEADER 107
+
+
+u_char *ngx_proxy_protocol_parse(ngx_connection_t *c, u_char *buf,
+ u_char *last);
+
+
+#endif /* _NGX_PROXY_PROTOCOL_H_INCLUDED_ */
diff --git a/usr.sbin/nginx/src/core/ngx_resolver.c b/usr.sbin/nginx/src/core/ngx_resolver.c
index d59d0c47162..645738ce531 100644
--- a/usr.sbin/nginx/src/core/ngx_resolver.c
+++ b/usr.sbin/nginx/src/core/ngx_resolver.c
@@ -26,7 +26,7 @@ typedef struct {
u_char nns_lo;
u_char nar_hi;
u_char nar_lo;
-} ngx_resolver_query_t;
+} ngx_resolver_hdr_t;
typedef struct {
@@ -70,7 +70,8 @@ static void ngx_resolver_read_response(ngx_event_t *rev);
static void ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf,
size_t n);
static void ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n,
- ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan, ngx_uint_t ans);
+ ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype,
+ ngx_uint_t nan, ngx_uint_t ans);
static void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan);
static ngx_resolver_node_t *ngx_resolver_lookup_name(ngx_resolver_t *r,
@@ -88,10 +89,17 @@ static void *ngx_resolver_calloc(ngx_resolver_t *r, size_t size);
static void ngx_resolver_free(ngx_resolver_t *r, void *p);
static void ngx_resolver_free_locked(ngx_resolver_t *r, void *p);
static void *ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size);
-static in_addr_t *ngx_resolver_rotate(ngx_resolver_t *r, in_addr_t *src,
- ngx_uint_t n);
+static ngx_addr_t *ngx_resolver_export(ngx_resolver_t *r,
+ ngx_resolver_node_t *rn, ngx_uint_t rotate);
static u_char *ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len);
+#if (NGX_HAVE_INET6)
+static void ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp,
+ ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
+static ngx_resolver_node_t *ngx_resolver_lookup_addr6(ngx_resolver_t *r,
+ struct in6_addr *addr, uint32_t hash);
+#endif
+
ngx_resolver_t *
ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n)
@@ -134,6 +142,17 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n)
ngx_queue_init(&r->name_expire_queue);
ngx_queue_init(&r->addr_expire_queue);
+#if (NGX_HAVE_INET6)
+ r->ipv6 = 1;
+
+ ngx_rbtree_init(&r->addr6_rbtree, &r->addr6_sentinel,
+ ngx_resolver_rbtree_insert_addr6_value);
+
+ ngx_queue_init(&r->addr6_resend_queue);
+
+ ngx_queue_init(&r->addr6_expire_queue);
+#endif
+
r->event->handler = ngx_resolver_resend_handler;
r->event->data = r;
r->event->log = &cf->cycle->new_log;
@@ -171,6 +190,25 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n)
continue;
}
+#if (NGX_HAVE_INET6)
+ if (ngx_strncmp(names[i].data, "ipv6=", 5) == 0) {
+
+ if (ngx_strcmp(&names[i].data[5], "on") == 0) {
+ r->ipv6 = 1;
+
+ } else if (ngx_strcmp(&names[i].data[5], "off") == 0) {
+ r->ipv6 = 0;
+
+ } else {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid parameter: %V", &names[i]);
+ return NULL;
+ }
+
+ continue;
+ }
+#endif
+
ngx_memzero(&u, sizeof(ngx_url_t));
u.url = names[i];
@@ -220,6 +258,10 @@ ngx_resolver_cleanup(void *data)
ngx_resolver_cleanup_tree(r, &r->addr_rbtree);
+#if (NGX_HAVE_INET6)
+ ngx_resolver_cleanup_tree(r, &r->addr6_rbtree);
+#endif
+
if (r->event) {
ngx_free(r->event);
}
@@ -281,7 +323,11 @@ ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp)
temp->state = NGX_OK;
temp->naddrs = 1;
temp->addrs = &temp->addr;
- temp->addr = addr;
+ temp->addr.sockaddr = (struct sockaddr *) &temp->sin;
+ temp->addr.socklen = sizeof(struct sockaddr_in);
+ ngx_memzero(&temp->sin, sizeof(struct sockaddr_in));
+ temp->sin.sin_family = AF_INET;
+ temp->sin.sin_addr.s_addr = addr;
temp->quick = 1;
return temp;
@@ -310,6 +356,10 @@ ngx_resolve_name(ngx_resolver_ctx_t *ctx)
r = ctx->resolver;
+ if (ctx->name.len > 0 && ctx->name.data[ctx->name.len - 1] == '.') {
+ ctx->name.len--;
+ }
+
ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
"resolve: \"%V\"", &ctx->name);
@@ -411,18 +461,18 @@ done:
}
-/* NGX_RESOLVE_A only */
-
static ngx_int_t
ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
{
uint32_t hash;
- in_addr_t addr, *addrs;
ngx_int_t rc;
ngx_uint_t naddrs;
+ ngx_addr_t *addrs;
ngx_resolver_ctx_t *next;
ngx_resolver_node_t *rn;
+ ngx_strlow(ctx->name.data, ctx->name.data, ctx->name.len);
+
hash = ngx_crc32_short(ctx->name.data, ctx->name.len);
rn = ngx_resolver_lookup_name(r, &ctx->name, hash);
@@ -439,22 +489,21 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
- naddrs = rn->naddrs;
+ naddrs = (rn->naddrs == (u_short) -1) ? 0 : rn->naddrs;
+#if (NGX_HAVE_INET6)
+ naddrs += (rn->naddrs6 == (u_short) -1) ? 0 : rn->naddrs6;
+#endif
if (naddrs) {
- /* NGX_RESOLVE_A answer */
+ if (naddrs == 1 && rn->naddrs == 1) {
+ addrs = NULL;
- if (naddrs != 1) {
- addr = 0;
- addrs = ngx_resolver_rotate(r, rn->u.addrs, naddrs);
+ } else {
+ addrs = ngx_resolver_export(r, rn, 1);
if (addrs == NULL) {
return NGX_ERROR;
}
-
- } else {
- addr = rn->u.addr;
- addrs = NULL;
}
ctx->next = rn->waiting;
@@ -465,8 +514,19 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
do {
ctx->state = NGX_OK;
ctx->naddrs = naddrs;
- ctx->addrs = (naddrs == 1) ? &ctx->addr : addrs;
- ctx->addr = addr;
+
+ if (addrs == NULL) {
+ ctx->addrs = &ctx->addr;
+ ctx->addr.sockaddr = (struct sockaddr *) &ctx->sin;
+ ctx->addr.socklen = sizeof(struct sockaddr_in);
+ ngx_memzero(&ctx->sin, sizeof(struct sockaddr_in));
+ ctx->sin.sin_family = AF_INET;
+ ctx->sin.sin_addr.s_addr = rn->u.addr;
+
+ } else {
+ ctx->addrs = addrs;
+ }
+
next = ctx->next;
ctx->handler(ctx);
@@ -474,7 +534,8 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
ctx = next;
} while (ctx);
- if (addrs) {
+ if (addrs != NULL) {
+ ngx_resolver_free(r, addrs->sockaddr);
ngx_resolver_free(r, addrs);
}
@@ -524,16 +585,25 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
if (rn->query) {
ngx_resolver_free_locked(r, rn->query);
rn->query = NULL;
+#if (NGX_HAVE_INET6)
+ rn->query6 = NULL;
+#endif
}
if (rn->cnlen) {
ngx_resolver_free_locked(r, rn->u.cname);
}
- if (rn->naddrs > 1) {
+ if (rn->naddrs > 1 && rn->naddrs != (u_short) -1) {
ngx_resolver_free_locked(r, rn->u.addrs);
}
+#if (NGX_HAVE_INET6)
+ if (rn->naddrs6 > 1 && rn->naddrs6 != (u_short) -1) {
+ ngx_resolver_free_locked(r, rn->u6.addrs6);
+ }
+#endif
+
/* unlock alloc mutex */
} else {
@@ -552,6 +622,9 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
rn->node.key = hash;
rn->nlen = (u_short) ctx->name.len;
rn->query = NULL;
+#if (NGX_HAVE_INET6)
+ rn->query6 = NULL;
+#endif
ngx_rbtree_insert(&r->name_rbtree, &rn->node);
}
@@ -575,6 +648,11 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
return NGX_OK;
}
+ rn->naddrs = (u_short) -1;
+#if (NGX_HAVE_INET6)
+ rn->naddrs6 = r->ipv6 ? (u_short) -1 : 0;
+#endif
+
if (ngx_resolver_send_query(r, rn) != NGX_OK) {
goto failed;
}
@@ -601,9 +679,10 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
ngx_queue_insert_head(&r->name_resend_queue, &rn->queue);
+ rn->code = 0;
rn->cnlen = 0;
- rn->naddrs = 0;
rn->valid = 0;
+ rn->ttl = NGX_MAX_UINT32_VALUE;
rn->waiting = ctx;
ctx->state = NGX_AGAIN;
@@ -630,16 +709,57 @@ ngx_int_t
ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
{
u_char *name;
+ in_addr_t addr;
+ ngx_queue_t *resend_queue, *expire_queue;
+ ngx_rbtree_t *tree;
ngx_resolver_t *r;
+ struct sockaddr_in *sin;
ngx_resolver_node_t *rn;
+#if (NGX_HAVE_INET6)
+ uint32_t hash;
+ struct sockaddr_in6 *sin6;
+#endif
+
+#if (NGX_SUPPRESS_WARN)
+ addr = 0;
+#if (NGX_HAVE_INET6)
+ hash = 0;
+ sin6 = NULL;
+#endif
+#endif
r = ctx->resolver;
- ctx->addr = ntohl(ctx->addr);
+ switch (ctx->addr.sockaddr->sa_family) {
- /* lock addr mutex */
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr;
+ hash = ngx_crc32_short(sin6->sin6_addr.s6_addr, 16);
+
+ /* lock addr mutex */
+
+ rn = ngx_resolver_lookup_addr6(r, &sin6->sin6_addr, hash);
+
+ tree = &r->addr6_rbtree;
+ resend_queue = &r->addr6_resend_queue;
+ expire_queue = &r->addr6_expire_queue;
+
+ break;
+#endif
+
+ default: /* AF_INET */
+ sin = (struct sockaddr_in *) ctx->addr.sockaddr;
+ addr = ntohl(sin->sin_addr.s_addr);
- rn = ngx_resolver_lookup_addr(r, ctx->addr);
+ /* lock addr mutex */
+
+ rn = ngx_resolver_lookup_addr(r, addr);
+
+ tree = &r->addr_rbtree;
+ resend_queue = &r->addr_resend_queue;
+ expire_queue = &r->addr_expire_queue;
+ }
if (rn) {
@@ -651,7 +771,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
rn->expire = ngx_time() + r->expire;
- ngx_queue_insert_head(&r->addr_expire_queue, &rn->queue);
+ ngx_queue_insert_head(expire_queue, &rn->queue);
name = ngx_resolver_dup(r, rn->name, rn->nlen);
if (name == NULL) {
@@ -687,6 +807,9 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
ngx_resolver_free(r, rn->query);
rn->query = NULL;
+#if (NGX_HAVE_INET6)
+ rn->query6 = NULL;
+#endif
} else {
rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t));
@@ -694,16 +817,36 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
goto failed;
}
- rn->node.key = ctx->addr;
+ switch (ctx->addr.sockaddr->sa_family) {
+
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ rn->addr6 = sin6->sin6_addr;
+ rn->node.key = hash;
+ break;
+#endif
+
+ default: /* AF_INET */
+ rn->node.key = addr;
+ }
+
rn->query = NULL;
+#if (NGX_HAVE_INET6)
+ rn->query6 = NULL;
+#endif
- ngx_rbtree_insert(&r->addr_rbtree, &rn->node);
+ ngx_rbtree_insert(tree, &rn->node);
}
if (ngx_resolver_create_addr_query(rn, ctx) != NGX_OK) {
goto failed;
}
+ rn->naddrs = (u_short) -1;
+#if (NGX_HAVE_INET6)
+ rn->naddrs6 = (u_short) -1;
+#endif
+
if (ngx_resolver_send_query(r, rn) != NGX_OK) {
goto failed;
}
@@ -720,19 +863,20 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
ngx_add_timer(ctx->event, ctx->timeout);
- if (ngx_queue_empty(&r->addr_resend_queue)) {
+ if (ngx_queue_empty(resend_queue)) {
ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000));
}
rn->expire = ngx_time() + r->resend_timeout;
- ngx_queue_insert_head(&r->addr_resend_queue, &rn->queue);
+ ngx_queue_insert_head(resend_queue, &rn->queue);
+ rn->code = 0;
rn->cnlen = 0;
- rn->naddrs = 0;
rn->name = NULL;
rn->nlen = 0;
rn->valid = 0;
+ rn->ttl = NGX_MAX_UINT32_VALUE;
rn->waiting = ctx;
/* unlock addr mutex */
@@ -744,7 +888,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
failed:
if (rn) {
- ngx_rbtree_delete(&r->addr_rbtree, &rn->node);
+ ngx_rbtree_delete(tree, &rn->node);
if (rn->query) {
ngx_resolver_free(r, rn->query);
@@ -769,12 +913,33 @@ void
ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)
{
in_addr_t addr;
+ ngx_queue_t *expire_queue;
+ ngx_rbtree_t *tree;
ngx_resolver_t *r;
ngx_resolver_ctx_t *w, **p;
+ struct sockaddr_in *sin;
ngx_resolver_node_t *rn;
+#if (NGX_HAVE_INET6)
+ uint32_t hash;
+ struct sockaddr_in6 *sin6;
+#endif
r = ctx->resolver;
+ switch (ctx->addr.sockaddr->sa_family) {
+
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ tree = &r->addr6_rbtree;
+ expire_queue = &r->addr6_expire_queue;
+ break;
+#endif
+
+ default: /* AF_INET */
+ tree = &r->addr_rbtree;
+ expire_queue = &r->addr_expire_queue;
+ }
+
ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
"resolve addr done: %i", ctx->state);
@@ -786,7 +951,21 @@ ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)
if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
- rn = ngx_resolver_lookup_addr(r, ctx->addr);
+ switch (ctx->addr.sockaddr->sa_family) {
+
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr;
+ hash = ngx_crc32_short(sin6->sin6_addr.s6_addr, 16);
+ rn = ngx_resolver_lookup_addr6(r, &sin6->sin6_addr, hash);
+ break;
+#endif
+
+ default: /* AF_INET */
+ sin = (struct sockaddr_in *) ctx->addr.sockaddr;
+ addr = ntohl(sin->sin_addr.s_addr);
+ rn = ngx_resolver_lookup_addr(r, addr);
+ }
if (rn) {
p = &rn->waiting;
@@ -804,17 +983,22 @@ ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)
}
}
- addr = ntohl(ctx->addr);
+ {
+ u_char text[NGX_SOCKADDR_STRLEN];
+ ngx_str_t addrtext;
- ngx_log_error(NGX_LOG_ALERT, r->log, 0,
- "could not cancel %ud.%ud.%ud.%ud resolving",
- (addr >> 24) & 0xff, (addr >> 16) & 0xff,
- (addr >> 8) & 0xff, addr & 0xff);
+ addrtext.data = text;
+ addrtext.len = ngx_sock_ntop(ctx->addr.sockaddr, ctx->addr.socklen,
+ text, NGX_SOCKADDR_STRLEN, 0);
+
+ ngx_log_error(NGX_LOG_ALERT, r->log, 0,
+ "could not cancel %V resolving", &addrtext);
+ }
}
done:
- ngx_resolver_expire(r, &r->addr_rbtree, &r->addr_expire_queue);
+ ngx_resolver_expire(r, tree, expire_queue);
/* unlock addr mutex */
@@ -896,16 +1080,33 @@ ngx_resolver_send_query(ngx_resolver_t *r, ngx_resolver_node_t *rn)
uc->connection->read->resolver = 1;
}
- n = ngx_send(uc->connection, rn->query, rn->qlen);
+ if (rn->naddrs == (u_short) -1) {
+ n = ngx_send(uc->connection, rn->query, rn->qlen);
- if (n == -1) {
- return NGX_ERROR;
+ if (n == -1) {
+ return NGX_ERROR;
+ }
+
+ if ((size_t) n != (size_t) rn->qlen) {
+ ngx_log_error(NGX_LOG_CRIT, &uc->log, 0, "send() incomplete");
+ return NGX_ERROR;
+ }
}
- if ((size_t) n != (size_t) rn->qlen) {
- ngx_log_error(NGX_LOG_CRIT, &uc->log, 0, "send() incomplete");
- return NGX_ERROR;
+#if (NGX_HAVE_INET6)
+ if (rn->query6 && rn->naddrs6 == (u_short) -1) {
+ n = ngx_send(uc->connection, rn->query6, rn->qlen);
+
+ if (n == -1) {
+ return NGX_ERROR;
+ }
+
+ if ((size_t) n != (size_t) rn->qlen) {
+ ngx_log_error(NGX_LOG_CRIT, &uc->log, 0, "send() incomplete");
+ return NGX_ERROR;
+ }
}
+#endif
return NGX_OK;
}
@@ -915,6 +1116,9 @@ static void
ngx_resolver_resend_handler(ngx_event_t *ev)
{
time_t timer, atimer, ntimer;
+#if (NGX_HAVE_INET6)
+ time_t a6timer;
+#endif
ngx_resolver_t *r;
r = ev->data;
@@ -934,16 +1138,36 @@ ngx_resolver_resend_handler(ngx_event_t *ev)
/* unlock addr mutex */
- if (ntimer == 0) {
+#if (NGX_HAVE_INET6)
+
+ /* lock addr6 mutex */
+
+ a6timer = ngx_resolver_resend(r, &r->addr6_rbtree, &r->addr6_resend_queue);
+
+ /* unlock addr6 mutex */
+
+#endif
+
+ timer = ntimer;
+
+ if (timer == 0) {
timer = atimer;
- } else if (atimer == 0) {
- timer = ntimer;
+ } else if (atimer) {
+ timer = ngx_min(timer, atimer);
+ }
- } else {
- timer = (atimer < ntimer) ? atimer : ntimer;
+#if (NGX_HAVE_INET6)
+
+ if (timer == 0) {
+ timer = a6timer;
+
+ } else if (a6timer) {
+ timer = ngx_min(timer, a6timer);
}
+#endif
+
if (timer) {
ngx_add_timer(r->event, (ngx_msec_t) (timer * 1000));
}
@@ -1021,39 +1245,42 @@ ngx_resolver_read_response(ngx_event_t *rev)
static void
ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n)
{
- char *err;
- size_t len;
- ngx_uint_t i, times, ident, qident, flags, code, nqs, nan,
- qtype, qclass;
- ngx_queue_t *q;
- ngx_resolver_qs_t *qs;
- ngx_resolver_node_t *rn;
- ngx_resolver_query_t *query;
-
- if ((size_t) n < sizeof(ngx_resolver_query_t)) {
+ char *err;
+ ngx_uint_t i, times, ident, qident, flags, code, nqs, nan,
+ qtype, qclass;
+#if (NGX_HAVE_INET6)
+ ngx_uint_t qident6;
+#endif
+ ngx_queue_t *q;
+ ngx_resolver_qs_t *qs;
+ ngx_resolver_hdr_t *response;
+ ngx_resolver_node_t *rn;
+
+ if (n < sizeof(ngx_resolver_hdr_t)) {
goto short_response;
}
- query = (ngx_resolver_query_t *) buf;
+ response = (ngx_resolver_hdr_t *) buf;
- ident = (query->ident_hi << 8) + query->ident_lo;
- flags = (query->flags_hi << 8) + query->flags_lo;
- nqs = (query->nqs_hi << 8) + query->nqs_lo;
- nan = (query->nan_hi << 8) + query->nan_lo;
+ ident = (response->ident_hi << 8) + response->ident_lo;
+ flags = (response->flags_hi << 8) + response->flags_lo;
+ nqs = (response->nqs_hi << 8) + response->nqs_lo;
+ nan = (response->nan_hi << 8) + response->nan_lo;
ngx_log_debug6(NGX_LOG_DEBUG_CORE, r->log, 0,
"resolver DNS response %ui fl:%04Xui %ui/%ui/%ud/%ud",
ident, flags, nqs, nan,
- (query->nns_hi << 8) + query->nns_lo,
- (query->nar_hi << 8) + query->nar_lo);
+ (response->nns_hi << 8) + response->nns_lo,
+ (response->nar_hi << 8) + response->nar_lo);
- if (!(flags & 0x8000)) {
+ /* response to a standard query */
+ if ((flags & 0xf870) != 0x8000) {
ngx_log_error(r->log_level, r->log, 0,
"invalid DNS response %ui fl:%04Xui", ident, flags);
return;
}
- code = flags & 0x7f;
+ code = flags & 0xf;
if (code == NGX_RESOLVE_FORMERR) {
@@ -1067,12 +1294,18 @@ ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n)
qident = (rn->query[0] << 8) + rn->query[1];
if (qident == ident) {
- ngx_log_error(r->log_level, r->log, 0,
- "DNS error (%ui: %s), query id:%ui, name:\"%*s\"",
- code, ngx_resolver_strerror(code), ident,
- rn->nlen, rn->name);
- return;
+ goto dns_error_name;
+ }
+
+#if (NGX_HAVE_INET6)
+ if (rn->query6) {
+ qident6 = (rn->query6[0] << 8) + rn->query6[1];
+
+ if (qident6 == ident) {
+ goto dns_error_name;
+ }
}
+#endif
}
goto dns_error;
@@ -1087,22 +1320,21 @@ ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n)
goto done;
}
- i = sizeof(ngx_resolver_query_t);
+ i = sizeof(ngx_resolver_hdr_t);
while (i < (ngx_uint_t) n) {
if (buf[i] == '\0') {
goto found;
}
- len = buf[i];
- i += 1 + len;
+ i += 1 + buf[i];
}
goto short_response;
found:
- if (i++ == 0) {
+ if (i++ == sizeof(ngx_resolver_hdr_t)) {
err = "zero-length domain name in DNS response";
goto done;
}
@@ -1130,8 +1362,11 @@ found:
switch (qtype) {
case NGX_RESOLVE_A:
+#if (NGX_HAVE_INET6)
+ case NGX_RESOLVE_AAAA:
+#endif
- ngx_resolver_process_a(r, buf, n, ident, code, nan,
+ ngx_resolver_process_a(r, buf, n, ident, code, qtype, nan,
i + sizeof(ngx_resolver_qs_t));
break;
@@ -1152,7 +1387,7 @@ found:
short_response:
- err = "short dns response";
+ err = "short DNS response";
done:
@@ -1160,6 +1395,14 @@ done:
return;
+dns_error_name:
+
+ ngx_log_error(r->log_level, r->log, 0,
+ "DNS error (%ui: %s), query id:%ui, name:\"%*s\"",
+ code, ngx_resolver_strerror(code), ident,
+ rn->nlen, rn->name);
+ return;
+
dns_error:
ngx_log_error(r->log_level, r->log, 0,
@@ -1171,21 +1414,29 @@ dns_error:
static void
ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
- ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan, ngx_uint_t ans)
+ ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype,
+ ngx_uint_t nan, ngx_uint_t ans)
{
char *err;
u_char *cname;
size_t len;
int32_t ttl;
uint32_t hash;
- in_addr_t addr, *addrs;
+ in_addr_t *addr;
ngx_str_t name;
- ngx_uint_t qtype, qident, naddrs, a, i, n, start;
+ ngx_addr_t *addrs;
+ ngx_uint_t type, class, qident, naddrs, a, i, n, start;
+#if (NGX_HAVE_INET6)
+ struct in6_addr *addr6;
+#endif
ngx_resolver_an_t *an;
ngx_resolver_ctx_t *ctx, *next;
ngx_resolver_node_t *rn;
- if (ngx_resolver_copy(r, &name, buf, &buf[12], &buf[last]) != NGX_OK) {
+ if (ngx_resolver_copy(r, &name, buf,
+ buf + sizeof(ngx_resolver_hdr_t), buf + last)
+ != NGX_OK)
+ {
return;
}
@@ -1197,28 +1448,113 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
rn = ngx_resolver_lookup_name(r, &name, hash);
- if (rn == NULL || rn->query == NULL) {
+ if (rn == NULL) {
ngx_log_error(r->log_level, r->log, 0,
"unexpected response for %V", &name);
+ ngx_resolver_free(r, name.data);
goto failed;
}
- qident = (rn->query[0] << 8) + rn->query[1];
+ switch (qtype) {
+
+#if (NGX_HAVE_INET6)
+ case NGX_RESOLVE_AAAA:
+
+ if (rn->query6 == NULL || rn->naddrs6 != (u_short) -1) {
+ ngx_log_error(r->log_level, r->log, 0,
+ "unexpected response for %V", &name);
+ ngx_resolver_free(r, name.data);
+ goto failed;
+ }
+
+ rn->naddrs6 = 0;
+ qident = (rn->query6[0] << 8) + rn->query6[1];
+
+ break;
+#endif
+
+ default: /* NGX_RESOLVE_A */
+
+ if (rn->query == NULL || rn->naddrs != (u_short) -1) {
+ ngx_log_error(r->log_level, r->log, 0,
+ "unexpected response for %V", &name);
+ ngx_resolver_free(r, name.data);
+ goto failed;
+ }
+
+ rn->naddrs = 0;
+ qident = (rn->query[0] << 8) + rn->query[1];
+ }
if (ident != qident) {
ngx_log_error(r->log_level, r->log, 0,
"wrong ident %ui response for %V, expect %ui",
ident, &name, qident);
+ ngx_resolver_free(r, name.data);
goto failed;
}
ngx_resolver_free(r, name.data);
+ if (code == 0 && rn->code) {
+ code = rn->code;
+ }
+
if (code == 0 && nan == 0) {
- code = 3; /* NXDOMAIN */
+
+#if (NGX_HAVE_INET6)
+ switch (qtype) {
+
+ case NGX_RESOLVE_AAAA:
+
+ if (rn->naddrs == (u_short) -1) {
+ goto next;
+ }
+
+ if (rn->naddrs) {
+ goto export;
+ }
+
+ break;
+
+ default: /* NGX_RESOLVE_A */
+
+ if (rn->naddrs6 == (u_short) -1) {
+ goto next;
+ }
+
+ if (rn->naddrs6) {
+ goto export;
+ }
+ }
+#endif
+
+ code = NGX_RESOLVE_NXDOMAIN;
}
if (code) {
+
+#if (NGX_HAVE_INET6)
+ switch (qtype) {
+
+ case NGX_RESOLVE_AAAA:
+
+ if (rn->naddrs == (u_short) -1) {
+ rn->code = (u_char) code;
+ goto next;
+ }
+
+ break;
+
+ default: /* NGX_RESOLVE_A */
+
+ if (rn->naddrs6 == (u_short) -1) {
+ rn->code = (u_char) code;
+ goto next;
+ }
+ }
+#endif
+
next = rn->waiting;
rn->waiting = NULL;
@@ -1231,11 +1567,11 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
/* unlock name mutex */
while (next) {
- ctx = next;
- ctx->state = code;
- next = ctx->next;
+ ctx = next;
+ ctx->state = code;
+ next = ctx->next;
- ctx->handler(ctx);
+ ctx->handler(ctx);
}
return;
@@ -1243,11 +1579,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
i = ans;
naddrs = 0;
- addr = 0;
- addrs = NULL;
cname = NULL;
- qtype = 0;
- ttl = 0;
for (a = 0; a < nan; a++) {
@@ -1273,7 +1605,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
test_length:
if (i - start < 2) {
- err = "invalid name in dns response";
+ err = "invalid name in DNS response";
goto invalid;
}
@@ -1285,115 +1617,239 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
an = (ngx_resolver_an_t *) &buf[i];
- qtype = (an->type_hi << 8) + an->type_lo;
+ type = (an->type_hi << 8) + an->type_lo;
+ class = (an->class_hi << 8) + an->class_lo;
len = (an->len_hi << 8) + an->len_lo;
ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16)
+ (an->ttl[2] << 8) + (an->ttl[3]);
+ if (class != 1) {
+ ngx_log_error(r->log_level, r->log, 0,
+ "unexpected RR class %ui", class);
+ goto failed;
+ }
+
if (ttl < 0) {
ttl = 0;
}
- if (qtype == NGX_RESOLVE_A) {
+ rn->ttl = ngx_min(rn->ttl, (uint32_t) ttl);
- i += sizeof(ngx_resolver_an_t);
+ i += sizeof(ngx_resolver_an_t);
+
+ switch (type) {
+
+ case NGX_RESOLVE_A:
+
+ if (qtype != NGX_RESOLVE_A) {
+ err = "unexpected A record in DNS response";
+ goto invalid;
+ }
- if (i + len > last) {
+ if (len != 4) {
+ err = "invalid A record in DNS response";
+ goto invalid;
+ }
+
+ if (i + 4 > last) {
goto short_response;
}
- addr = htonl((buf[i] << 24) + (buf[i + 1] << 16)
- + (buf[i + 2] << 8) + (buf[i + 3]));
+ naddrs++;
+
+ break;
+
+#if (NGX_HAVE_INET6)
+ case NGX_RESOLVE_AAAA:
+
+ if (qtype != NGX_RESOLVE_AAAA) {
+ err = "unexpected AAAA record in DNS response";
+ goto invalid;
+ }
+
+ if (len != 16) {
+ err = "invalid AAAA record in DNS response";
+ goto invalid;
+ }
+
+ if (i + 16 > last) {
+ goto short_response;
+ }
naddrs++;
- i += len;
+ break;
+#endif
- } else if (qtype == NGX_RESOLVE_CNAME) {
- cname = &buf[i] + sizeof(ngx_resolver_an_t);
- i += sizeof(ngx_resolver_an_t) + len;
+ case NGX_RESOLVE_CNAME:
- } else if (qtype == NGX_RESOLVE_DNAME) {
- i += sizeof(ngx_resolver_an_t) + len;
+ cname = &buf[i];
+
+ break;
+
+ case NGX_RESOLVE_DNAME:
+
+ break;
+
+ default:
- } else {
ngx_log_error(r->log_level, r->log, 0,
- "unexpected qtype %ui", qtype);
+ "unexpected RR type %ui", type);
}
+
+ i += len;
}
ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
- "resolver naddrs:%ui cname:%p ttl:%d",
- naddrs, cname, ttl);
+ "resolver naddrs:%ui cname:%p ttl:%uD",
+ naddrs, cname, rn->ttl);
if (naddrs) {
- if (naddrs == 1) {
- rn->u.addr = addr;
+ switch (qtype) {
- } else {
+#if (NGX_HAVE_INET6)
+ case NGX_RESOLVE_AAAA:
- addrs = ngx_resolver_alloc(r, naddrs * sizeof(in_addr_t));
- if (addrs == NULL) {
- return;
+ if (naddrs == 1) {
+ addr6 = &rn->u6.addr6;
+ rn->naddrs6 = 1;
+
+ } else {
+ addr6 = ngx_resolver_alloc(r, naddrs * sizeof(struct in6_addr));
+ if (addr6 == NULL) {
+ goto failed;
+ }
+
+ rn->u6.addrs6 = addr6;
+ rn->naddrs6 = (u_short) naddrs;
}
- n = 0;
- i = ans;
+#if (NGX_SUPPRESS_WARN)
+ addr = NULL;
+#endif
- for (a = 0; a < nan; a++) {
+ break;
+#endif
- for ( ;; ) {
+ default: /* NGX_RESOLVE_A */
- if (buf[i] & 0xc0) {
- i += 2;
- goto ok;
- }
+ if (naddrs == 1) {
+ addr = &rn->u.addr;
+ rn->naddrs = 1;
- if (buf[i] == 0) {
- i++;
- goto ok;
- }
+ } else {
+ addr = ngx_resolver_alloc(r, naddrs * sizeof(in_addr_t));
+ if (addr == NULL) {
+ goto failed;
+ }
+
+ rn->u.addrs = addr;
+ rn->naddrs = (u_short) naddrs;
+ }
+
+#if (NGX_HAVE_INET6 && NGX_SUPPRESS_WARN)
+ addr6 = NULL;
+#endif
+ }
- i += 1 + buf[i];
+ n = 0;
+ i = ans;
+
+ for (a = 0; a < nan; a++) {
+
+ for ( ;; ) {
+
+ if (buf[i] & 0xc0) {
+ i += 2;
+ break;
+ }
+
+ if (buf[i] == 0) {
+ i++;
+ break;
}
- ok:
+ i += 1 + buf[i];
+ }
+
+ an = (ngx_resolver_an_t *) &buf[i];
- an = (ngx_resolver_an_t *) &buf[i];
+ type = (an->type_hi << 8) + an->type_lo;
+ len = (an->len_hi << 8) + an->len_lo;
- qtype = (an->type_hi << 8) + an->type_lo;
- len = (an->len_hi << 8) + an->len_lo;
+ i += sizeof(ngx_resolver_an_t);
- i += sizeof(ngx_resolver_an_t);
+ if (type == NGX_RESOLVE_A) {
- if (qtype == NGX_RESOLVE_A) {
+ addr[n] = htonl((buf[i] << 24) + (buf[i + 1] << 16)
+ + (buf[i + 2] << 8) + (buf[i + 3]));
- addrs[n++] = htonl((buf[i] << 24) + (buf[i + 1] << 16)
- + (buf[i + 2] << 8) + (buf[i + 3]));
+ if (++n == naddrs) {
- if (n == naddrs) {
- break;
+#if (NGX_HAVE_INET6)
+ if (rn->naddrs6 == (u_short) -1) {
+ goto next;
}
+#endif
+
+ break;
}
+ }
+
+#if (NGX_HAVE_INET6)
+ else if (type == NGX_RESOLVE_AAAA) {
+
+ ngx_memcpy(addr6[n].s6_addr, &buf[i], 16);
+
+ if (++n == naddrs) {
+
+ if (rn->naddrs == (u_short) -1) {
+ goto next;
+ }
- i += len;
+ break;
+ }
}
+#endif
- rn->u.addrs = addrs;
+ i += len;
+ }
+ }
- addrs = ngx_resolver_dup(r, rn->u.addrs,
- naddrs * sizeof(in_addr_t));
+ if (rn->naddrs != (u_short) -1
+#if (NGX_HAVE_INET6)
+ && rn->naddrs6 != (u_short) -1
+#endif
+ && rn->naddrs
+#if (NGX_HAVE_INET6)
+ + rn->naddrs6
+#endif
+ > 0)
+ {
+
+#if (NGX_HAVE_INET6)
+ export:
+#endif
+
+ naddrs = rn->naddrs;
+#if (NGX_HAVE_INET6)
+ naddrs += rn->naddrs6;
+#endif
+
+ if (naddrs == 1 && rn->naddrs == 1) {
+ addrs = NULL;
+
+ } else {
+ addrs = ngx_resolver_export(r, rn, 0);
if (addrs == NULL) {
- return;
+ goto failed;
}
}
- rn->naddrs = (u_short) naddrs;
-
ngx_queue_remove(&rn->queue);
- rn->valid = ngx_time() + (r->valid ? r->valid : ttl);
+ rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl);
rn->expire = ngx_time() + r->expire;
ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
@@ -1404,31 +1860,56 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
/* unlock name mutex */
while (next) {
- ctx = next;
- ctx->state = NGX_OK;
- ctx->naddrs = naddrs;
- ctx->addrs = (naddrs == 1) ? &ctx->addr : addrs;
- ctx->addr = addr;
- next = ctx->next;
+ ctx = next;
+ ctx->state = NGX_OK;
+ ctx->naddrs = naddrs;
+
+ if (addrs == NULL) {
+ ctx->addrs = &ctx->addr;
+ ctx->addr.sockaddr = (struct sockaddr *) &ctx->sin;
+ ctx->addr.socklen = sizeof(struct sockaddr_in);
+ ngx_memzero(&ctx->sin, sizeof(struct sockaddr_in));
+ ctx->sin.sin_family = AF_INET;
+ ctx->sin.sin_addr.s_addr = rn->u.addr;
+
+ } else {
+ ctx->addrs = addrs;
+ }
- ctx->handler(ctx);
+ next = ctx->next;
+
+ ctx->handler(ctx);
}
- if (naddrs > 1) {
+ if (addrs != NULL) {
+ ngx_resolver_free(r, addrs->sockaddr);
ngx_resolver_free(r, addrs);
}
ngx_resolver_free(r, rn->query);
rn->query = NULL;
+#if (NGX_HAVE_INET6)
+ rn->query6 = NULL;
+#endif
return;
+ }
- } else if (cname) {
+ if (cname) {
/* CNAME only */
- if (ngx_resolver_copy(r, &name, buf, cname, &buf[last]) != NGX_OK) {
- return;
+ if (rn->naddrs == (u_short) -1
+#if (NGX_HAVE_INET6)
+ || rn->naddrs6 == (u_short) -1
+#endif
+ )
+ {
+ goto next;
+ }
+
+ if (ngx_resolver_copy(r, &name, buf, cname, buf + last) != NGX_OK) {
+ goto failed;
}
ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
@@ -1439,7 +1920,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
rn->cnlen = (u_short) name.len;
rn->u.cname = name.data;
- rn->valid = ngx_time() + (r->valid ? r->valid : ttl);
+ rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl);
rn->expire = ngx_time() + r->expire;
ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
@@ -1455,18 +1936,22 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
ngx_resolver_free(r, rn->query);
rn->query = NULL;
+#if (NGX_HAVE_INET6)
+ rn->query6 = NULL;
+#endif
+
+ /* unlock name mutex */
return;
}
ngx_log_error(r->log_level, r->log, 0,
- "no A or CNAME types in DNS responses, unknown query type: %ui",
- qtype);
+ "no A or CNAME types in DNS response");
return;
short_response:
- err = "short dns response";
+ err = "short DNS response";
invalid:
@@ -1478,9 +1963,9 @@ invalid:
failed:
- /* unlock name mutex */
+next:
- ngx_resolver_free(r, name.data);
+ /* unlock name mutex */
return;
}
@@ -1492,47 +1977,123 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
{
char *err;
size_t len;
+ u_char text[NGX_SOCKADDR_STRLEN];
in_addr_t addr;
int32_t ttl;
- ngx_int_t digit;
+ ngx_int_t octet;
ngx_str_t name;
- ngx_uint_t i, mask, qident;
+ ngx_uint_t i, mask, qident, class;
+ ngx_queue_t *expire_queue;
+ ngx_rbtree_t *tree;
ngx_resolver_an_t *an;
ngx_resolver_ctx_t *ctx, *next;
ngx_resolver_node_t *rn;
+#if (NGX_HAVE_INET6)
+ uint32_t hash;
+ ngx_int_t digit;
+ struct in6_addr addr6;
+#endif
- if (ngx_resolver_copy(r, NULL, buf, &buf[12], &buf[n]) != NGX_OK) {
- goto invalid_in_addr_arpa;
+ if (ngx_resolver_copy(r, NULL, buf,
+ buf + sizeof(ngx_resolver_hdr_t), buf + n)
+ != NGX_OK)
+ {
+ return;
}
+ /* AF_INET */
+
addr = 0;
- i = 12;
+ i = sizeof(ngx_resolver_hdr_t);
for (mask = 0; mask < 32; mask += 8) {
len = buf[i++];
- digit = ngx_atoi(&buf[i], len);
- if (digit == NGX_ERROR || digit > 255) {
+ octet = ngx_atoi(&buf[i], len);
+ if (octet == NGX_ERROR || octet > 255) {
goto invalid_in_addr_arpa;
}
- addr += digit << mask;
+ addr += octet << mask;
i += len;
}
- if (ngx_strcmp(&buf[i], "\7in-addr\4arpa") != 0) {
- goto invalid_in_addr_arpa;
+ if (ngx_strcasecmp(&buf[i], (u_char *) "\7in-addr\4arpa") == 0) {
+ i += sizeof("\7in-addr\4arpa");
+
+ /* lock addr mutex */
+
+ rn = ngx_resolver_lookup_addr(r, addr);
+
+ tree = &r->addr_rbtree;
+ expire_queue = &r->addr_expire_queue;
+
+ addr = htonl(addr);
+ name.len = ngx_inet_ntop(AF_INET, &addr, text, NGX_SOCKADDR_STRLEN);
+ name.data = text;
+
+ goto valid;
}
- /* lock addr mutex */
+invalid_in_addr_arpa:
+
+#if (NGX_HAVE_INET6)
+
+ i = sizeof(ngx_resolver_hdr_t);
+
+ for (octet = 15; octet >= 0; octet--) {
+ if (buf[i++] != '\1') {
+ goto invalid_ip6_arpa;
+ }
+
+ digit = ngx_hextoi(&buf[i++], 1);
+ if (digit == NGX_ERROR) {
+ goto invalid_ip6_arpa;
+ }
+
+ addr6.s6_addr[octet] = (u_char) digit;
+
+ if (buf[i++] != '\1') {
+ goto invalid_ip6_arpa;
+ }
+
+ digit = ngx_hextoi(&buf[i++], 1);
+ if (digit == NGX_ERROR) {
+ goto invalid_ip6_arpa;
+ }
+
+ addr6.s6_addr[octet] += (u_char) (digit * 16);
+ }
+
+ if (ngx_strcasecmp(&buf[i], (u_char *) "\3ip6\4arpa") == 0) {
+ i += sizeof("\3ip6\4arpa");
+
+ /* lock addr mutex */
+
+ hash = ngx_crc32_short(addr6.s6_addr, 16);
+ rn = ngx_resolver_lookup_addr6(r, &addr6, hash);
+
+ tree = &r->addr6_rbtree;
+ expire_queue = &r->addr6_expire_queue;
+
+ name.len = ngx_inet6_ntop(addr6.s6_addr, text, NGX_SOCKADDR_STRLEN);
+ name.data = text;
+
+ goto valid;
+ }
- rn = ngx_resolver_lookup_addr(r, addr);
+invalid_ip6_arpa:
+#endif
+
+ ngx_log_error(r->log_level, r->log, 0,
+ "invalid in-addr.arpa or ip6.arpa name in DNS response");
+ return;
+
+valid:
if (rn == NULL || rn->query == NULL) {
ngx_log_error(r->log_level, r->log, 0,
- "unexpected response for %ud.%ud.%ud.%ud",
- (addr >> 24) & 0xff, (addr >> 16) & 0xff,
- (addr >> 8) & 0xff, addr & 0xff);
+ "unexpected response for %V", &name);
goto failed;
}
@@ -1540,14 +2101,13 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
if (ident != qident) {
ngx_log_error(r->log_level, r->log, 0,
- "wrong ident %ui response for %ud.%ud.%ud.%ud, expect %ui",
- ident, (addr >> 24) & 0xff, (addr >> 16) & 0xff,
- (addr >> 8) & 0xff, addr & 0xff, qident);
+ "wrong ident %ui response for %V, expect %ui",
+ ident, &name, qident);
goto failed;
}
if (code == 0 && nan == 0) {
- code = 3; /* NXDOMAIN */
+ code = NGX_RESOLVE_NXDOMAIN;
}
if (code) {
@@ -1556,42 +2116,49 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
ngx_queue_remove(&rn->queue);
- ngx_rbtree_delete(&r->addr_rbtree, &rn->node);
+ ngx_rbtree_delete(tree, &rn->node);
ngx_resolver_free_node(r, rn);
/* unlock addr mutex */
while (next) {
- ctx = next;
- ctx->state = code;
- next = ctx->next;
+ ctx = next;
+ ctx->state = code;
+ next = ctx->next;
- ctx->handler(ctx);
+ ctx->handler(ctx);
}
return;
}
- i += sizeof("\7in-addr\4arpa") + sizeof(ngx_resolver_qs_t);
+ i += sizeof(ngx_resolver_qs_t);
- if (i + 2 + sizeof(ngx_resolver_an_t) > (ngx_uint_t) n) {
+ if (i + 2 + sizeof(ngx_resolver_an_t) >= n) {
goto short_response;
}
- /* compression pointer to "XX.XX.XX.XX.in-addr.arpa */
+ /* compression pointer to *.arpa */
- if (buf[i] != 0xc0 || buf[i + 1] != 0x0c) {
- err = "invalid in-addr.arpa name in DNS response";
+ if (buf[i] != 0xc0 || buf[i + 1] != sizeof(ngx_resolver_hdr_t)) {
+ err = "invalid in-addr.arpa or ip6.arpa name in DNS response";
goto invalid;
}
an = (ngx_resolver_an_t *) &buf[i + 2];
+ class = (an->class_hi << 8) + an->class_lo;
len = (an->len_hi << 8) + an->len_lo;
ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16)
+ (an->ttl[2] << 8) + (an->ttl[3]);
+ if (class != 1) {
+ ngx_log_error(r->log_level, r->log, 0,
+ "unexpected RR class %ui", class);
+ goto failed;
+ }
+
if (ttl < 0) {
ttl = 0;
}
@@ -1599,16 +2166,16 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
"resolver qt:%ui cl:%ui len:%uz",
(an->type_hi << 8) + an->type_lo,
- (an->class_hi << 8) + an->class_lo, len);
+ class, len);
i += 2 + sizeof(ngx_resolver_an_t);
- if (i + len > (ngx_uint_t) n) {
+ if (i + len > n) {
goto short_response;
}
- if (ngx_resolver_copy(r, &name, buf, &buf[i], &buf[n]) != NGX_OK) {
- return;
+ if (ngx_resolver_copy(r, &name, buf, buf + i, buf + n) != NGX_OK) {
+ goto failed;
}
ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver an:%V", &name);
@@ -1634,7 +2201,7 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
rn->valid = ngx_time() + (r->valid ? r->valid : ttl);
rn->expire = ngx_time() + r->expire;
- ngx_queue_insert_head(&r->addr_expire_queue, &rn->queue);
+ ngx_queue_insert_head(expire_queue, &rn->queue);
next = rn->waiting;
rn->waiting = NULL;
@@ -1642,24 +2209,18 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
/* unlock addr mutex */
while (next) {
- ctx = next;
- ctx->state = NGX_OK;
- ctx->name = name;
- next = ctx->next;
+ ctx = next;
+ ctx->state = NGX_OK;
+ ctx->name = name;
+ next = ctx->next;
- ctx->handler(ctx);
+ ctx->handler(ctx);
}
ngx_resolver_free(r, name.data);
return;
-invalid_in_addr_arpa:
-
- ngx_log_error(r->log_level, r->log, 0,
- "invalid in-addr.arpa name in DNS response");
- return;
-
short_response:
err = "short DNS response";
@@ -1752,6 +2313,52 @@ ngx_resolver_lookup_addr(ngx_resolver_t *r, in_addr_t addr)
}
+#if (NGX_HAVE_INET6)
+
+static ngx_resolver_node_t *
+ngx_resolver_lookup_addr6(ngx_resolver_t *r, struct in6_addr *addr,
+ uint32_t hash)
+{
+ ngx_int_t rc;
+ ngx_rbtree_node_t *node, *sentinel;
+ ngx_resolver_node_t *rn;
+
+ node = r->addr6_rbtree.root;
+ sentinel = r->addr6_rbtree.sentinel;
+
+ while (node != sentinel) {
+
+ if (hash < node->key) {
+ node = node->left;
+ continue;
+ }
+
+ if (hash > node->key) {
+ node = node->right;
+ continue;
+ }
+
+ /* hash == node->key */
+
+ rn = (ngx_resolver_node_t *) node;
+
+ rc = ngx_memcmp(addr, &rn->addr6, 16);
+
+ if (rc == 0) {
+ return rn;
+ }
+
+ node = (rc < 0) ? node->left : node->right;
+ }
+
+ /* not found */
+
+ return NULL;
+}
+
+#endif
+
+
static void
ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
@@ -1793,20 +2400,74 @@ ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
}
+#if (NGX_HAVE_INET6)
+
+static void
+ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp,
+ ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
+{
+ ngx_rbtree_node_t **p;
+ ngx_resolver_node_t *rn, *rn_temp;
+
+ for ( ;; ) {
+
+ if (node->key < temp->key) {
+
+ p = &temp->left;
+
+ } else if (node->key > temp->key) {
+
+ p = &temp->right;
+
+ } else { /* node->key == temp->key */
+
+ rn = (ngx_resolver_node_t *) node;
+ rn_temp = (ngx_resolver_node_t *) temp;
+
+ p = (ngx_memcmp(&rn->addr6, &rn_temp->addr6, 16)
+ < 0) ? &temp->left : &temp->right;
+ }
+
+ if (*p == sentinel) {
+ break;
+ }
+
+ temp = *p;
+ }
+
+ *p = node;
+ node->parent = temp;
+ node->left = sentinel;
+ node->right = sentinel;
+ ngx_rbt_red(node);
+}
+
+#endif
+
+
static ngx_int_t
ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
{
- u_char *p, *s;
- size_t len, nlen;
- ngx_uint_t ident;
- ngx_resolver_qs_t *qs;
- ngx_resolver_query_t *query;
+ u_char *p, *s;
+ size_t len, nlen;
+ ngx_uint_t ident;
+#if (NGX_HAVE_INET6)
+ ngx_resolver_t *r;
+#endif
+ ngx_resolver_qs_t *qs;
+ ngx_resolver_hdr_t *query;
nlen = ctx->name.len ? (1 + ctx->name.len + 1) : 1;
- len = sizeof(ngx_resolver_query_t) + nlen + sizeof(ngx_resolver_qs_t);
+ len = sizeof(ngx_resolver_hdr_t) + nlen + sizeof(ngx_resolver_qs_t);
+#if (NGX_HAVE_INET6)
+ r = ctx->resolver;
+
+ p = ngx_resolver_alloc(ctx->resolver, r->ipv6 ? len * 2 : len);
+#else
p = ngx_resolver_alloc(ctx->resolver, len);
+#endif
if (p == NULL) {
return NGX_ERROR;
}
@@ -1814,12 +2475,18 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
rn->qlen = (u_short) len;
rn->query = p;
- query = (ngx_resolver_query_t *) p;
+#if (NGX_HAVE_INET6)
+ if (r->ipv6) {
+ rn->query6 = p + len;
+ }
+#endif
+
+ query = (ngx_resolver_hdr_t *) p;
ident = ngx_random();
ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0,
- "resolve: \"%V\" %i", &ctx->name, ident & 0xffff);
+ "resolve: \"%V\" A %i", &ctx->name, ident & 0xffff);
query->ident_hi = (u_char) ((ident >> 8) & 0xff);
query->ident_lo = (u_char) (ident & 0xff);
@@ -1833,14 +2500,14 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
query->nns_hi = 0; query->nns_lo = 0;
query->nar_hi = 0; query->nar_lo = 0;
- p += sizeof(ngx_resolver_query_t) + nlen;
+ p += sizeof(ngx_resolver_hdr_t) + nlen;
qs = (ngx_resolver_qs_t *) p;
/* query type */
- qs->type_hi = 0; qs->type_lo = (u_char) ctx->type;
+ qs->type_hi = 0; qs->type_lo = NGX_RESOLVE_A;
- /* IP query class */
+ /* IN query class */
qs->class_hi = 0; qs->class_lo = 1;
/* convert "www.example.com" to "\3www\7example\3com\0" */
@@ -1876,24 +2543,66 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
*p = (u_char) len;
+#if (NGX_HAVE_INET6)
+ if (!r->ipv6) {
+ return NGX_OK;
+ }
+
+ p = rn->query6;
+
+ ngx_memcpy(p, rn->query, rn->qlen);
+
+ query = (ngx_resolver_hdr_t *) p;
+
+ ident = ngx_random();
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0,
+ "resolve: \"%V\" AAAA %i", &ctx->name, ident & 0xffff);
+
+ query->ident_hi = (u_char) ((ident >> 8) & 0xff);
+ query->ident_lo = (u_char) (ident & 0xff);
+
+ p += sizeof(ngx_resolver_hdr_t) + nlen;
+
+ qs = (ngx_resolver_qs_t *) p;
+
+ qs->type_lo = NGX_RESOLVE_AAAA;
+#endif
+
return NGX_OK;
}
-/* AF_INET only */
-
static ngx_int_t
ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
{
- u_char *p, *d;
- size_t len;
- ngx_int_t n;
- ngx_uint_t ident;
- ngx_resolver_query_t *query;
+ u_char *p, *d;
+ size_t len;
+ in_addr_t addr;
+ ngx_int_t n;
+ ngx_uint_t ident;
+ ngx_resolver_hdr_t *query;
+ struct sockaddr_in *sin;
+#if (NGX_HAVE_INET6)
+ struct sockaddr_in6 *sin6;
+#endif
+
+ switch (ctx->addr.sockaddr->sa_family) {
- len = sizeof(ngx_resolver_query_t)
- + sizeof(".255.255.255.255.in-addr.arpa.") - 1
- + sizeof(ngx_resolver_qs_t);
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ len = sizeof(ngx_resolver_hdr_t)
+ + 64 + sizeof(".ip6.arpa.") - 1
+ + sizeof(ngx_resolver_qs_t);
+
+ break;
+#endif
+
+ default: /* AF_INET */
+ len = sizeof(ngx_resolver_hdr_t)
+ + sizeof(".255.255.255.255.in-addr.arpa.") - 1
+ + sizeof(ngx_resolver_qs_t);
+ }
p = ngx_resolver_alloc(ctx->resolver, len);
if (p == NULL) {
@@ -1901,7 +2610,7 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
}
rn->query = p;
- query = (ngx_resolver_query_t *) p;
+ query = (ngx_resolver_hdr_t *) p;
ident = ngx_random();
@@ -1917,20 +2626,43 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
query->nns_hi = 0; query->nns_lo = 0;
query->nar_hi = 0; query->nar_lo = 0;
- p += sizeof(ngx_resolver_query_t);
+ p += sizeof(ngx_resolver_hdr_t);
+
+ switch (ctx->addr.sockaddr->sa_family) {
+
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr;
+
+ for (n = 15; n >= 0; n--) {
+ p = ngx_sprintf(p, "\1%xd\1%xd",
+ sin6->sin6_addr.s6_addr[n] & 0xf,
+ (sin6->sin6_addr.s6_addr[n] >> 4) & 0xf);
+ }
+
+ p = ngx_cpymem(p, "\3ip6\4arpa\0", 10);
- for (n = 0; n < 32; n += 8) {
- d = ngx_sprintf(&p[1], "%ud", (ctx->addr >> n) & 0xff);
- *p = (u_char) (d - &p[1]);
- p = d;
+ break;
+#endif
+
+ default: /* AF_INET */
+
+ sin = (struct sockaddr_in *) ctx->addr.sockaddr;
+ addr = ntohl(sin->sin_addr.s_addr);
+
+ for (n = 0; n < 32; n += 8) {
+ d = ngx_sprintf(&p[1], "%ud", (addr >> n) & 0xff);
+ *p = (u_char) (d - &p[1]);
+ p = d;
+ }
+
+ p = ngx_cpymem(p, "\7in-addr\4arpa\0", 14);
}
- /* query type "PTR", IP query class */
- ngx_memcpy(p, "\7in-addr\4arpa\0\0\14\0\1", 18);
+ /* query type "PTR", IN query class */
+ p = ngx_cpymem(p, "\0\14\0\1", 4);
- rn->qlen = (u_short)
- (p + sizeof("\7in-addr\4arpa") + sizeof(ngx_resolver_qs_t)
- - rn->query);
+ rn->qlen = (u_short) (p - rn->query);
return NGX_OK;
}
@@ -2012,7 +2744,7 @@ done:
n = *src++;
} else {
- ngx_memcpy(dst, src, n);
+ ngx_strlow(dst, src, n);
dst += n;
src += n;
@@ -2061,10 +2793,16 @@ ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn)
ngx_resolver_free_locked(r, rn->u.cname);
}
- if (rn->naddrs > 1) {
+ if (rn->naddrs > 1 && rn->naddrs != (u_short) -1) {
ngx_resolver_free_locked(r, rn->u.addrs);
}
+#if (NGX_HAVE_INET6)
+ if (rn->naddrs6 > 1 && rn->naddrs6 != (u_short) -1) {
+ ngx_resolver_free_locked(r, rn->u6.addrs6);
+ }
+#endif
+
ngx_resolver_free_locked(r, rn);
/* unlock alloc mutex */
@@ -2136,27 +2874,84 @@ ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size)
}
-static in_addr_t *
-ngx_resolver_rotate(ngx_resolver_t *r, in_addr_t *src, ngx_uint_t n)
+static ngx_addr_t *
+ngx_resolver_export(ngx_resolver_t *r, ngx_resolver_node_t *rn,
+ ngx_uint_t rotate)
{
- void *dst, *p;
- ngx_uint_t j;
+ ngx_addr_t *dst;
+ ngx_uint_t d, i, j, n;
+ u_char (*sockaddr)[NGX_SOCKADDRLEN];
+ in_addr_t *addr;
+ struct sockaddr_in *sin;
+#if (NGX_HAVE_INET6)
+ struct in6_addr *addr6;
+ struct sockaddr_in6 *sin6;
+#endif
- dst = ngx_resolver_alloc(r, n * sizeof(in_addr_t));
+ n = rn->naddrs;
+#if (NGX_HAVE_INET6)
+ n += rn->naddrs6;
+#endif
+ dst = ngx_resolver_calloc(r, n * sizeof(ngx_addr_t));
if (dst == NULL) {
- return dst;
+ return NULL;
}
- j = ngx_random() % n;
+ sockaddr = ngx_resolver_calloc(r, n * NGX_SOCKADDRLEN);
+ if (sockaddr == NULL) {
+ ngx_resolver_free(r, dst);
+ return NULL;
+ }
- if (j == 0) {
- ngx_memcpy(dst, src, n * sizeof(in_addr_t));
- return dst;
+ i = 0;
+ d = rotate ? ngx_random() % n : 0;
+
+ if (rn->naddrs) {
+ j = rotate ? ngx_random() % rn->naddrs : 0;
+
+ addr = (rn->naddrs == 1) ? &rn->u.addr : rn->u.addrs;
+
+ do {
+ sin = (struct sockaddr_in *) sockaddr[d];
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = addr[j++];
+ dst[d].sockaddr = (struct sockaddr *) sin;
+ dst[d++].socklen = sizeof(struct sockaddr_in);
+
+ if (d == n) {
+ d = 0;
+ }
+
+ if (j == rn->naddrs) {
+ j = 0;
+ }
+ } while (++i < rn->naddrs);
}
- p = ngx_cpymem(dst, &src[j], (n - j) * sizeof(in_addr_t));
- ngx_memcpy(p, src, j * sizeof(in_addr_t));
+#if (NGX_HAVE_INET6)
+ if (rn->naddrs6) {
+ j = rotate ? ngx_random() % rn->naddrs6 : 0;
+
+ addr6 = (rn->naddrs6 == 1) ? &rn->u6.addr6 : rn->u6.addrs6;
+
+ do {
+ sin6 = (struct sockaddr_in6 *) sockaddr[d];
+ sin6->sin6_family = AF_INET6;
+ ngx_memcpy(sin6->sin6_addr.s6_addr, addr6[j++].s6_addr, 16);
+ dst[d].sockaddr = (struct sockaddr *) sin6;
+ dst[d++].socklen = sizeof(struct sockaddr_in6);
+
+ if (d == n) {
+ d = 0;
+ }
+
+ if (j == rn->naddrs6) {
+ j = 0;
+ }
+ } while (++i < n);
+ }
+#endif
return dst;
}
@@ -2221,7 +3016,7 @@ ngx_udp_connect(ngx_udp_connection_t *uc)
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &uc->log, 0, "UDP socket %d", s);
- if (s == -1) {
+ if (s == (ngx_socket_t) -1) {
ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno,
ngx_socket_n " failed");
return NGX_ERROR;
@@ -2242,14 +3037,7 @@ ngx_udp_connect(ngx_udp_connection_t *uc)
ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno,
ngx_nonblocking_n " failed");
- ngx_free_connection(c);
-
- if (ngx_close_socket(s) == -1) {
- ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno,
- ngx_close_socket_n " failed");
- }
-
- return NGX_ERROR;
+ goto failed;
}
rev = c->read;
@@ -2274,7 +3062,7 @@ ngx_udp_connect(ngx_udp_connection_t *uc)
#endif
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &uc->log, 0,
- "connect to %V, fd:%d #%d", &uc->server, s, c->number);
+ "connect to %V, fd:%d #%uA", &uc->server, s, c->number);
rc = connect(s, uc->sockaddr, uc->socklen);
@@ -2284,7 +3072,7 @@ ngx_udp_connect(ngx_udp_connection_t *uc)
ngx_log_error(NGX_LOG_CRIT, &uc->log, ngx_socket_errno,
"connect() failed");
- return NGX_ERROR;
+ goto failed;
}
/* UDP sockets are always ready to write */
@@ -2298,16 +3086,23 @@ ngx_udp_connect(ngx_udp_connection_t *uc)
/* eventport event type has no meaning: oneshot only */
if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
- return NGX_ERROR;
+ goto failed;
}
} else {
/* rtsig */
if (ngx_add_conn(c) == NGX_ERROR) {
- return NGX_ERROR;
+ goto failed;
}
}
return NGX_OK;
+
+failed:
+
+ ngx_close_connection(c);
+ uc->connection = NULL;
+
+ return NGX_ERROR;
}
diff --git a/usr.sbin/nginx/src/core/ngx_resolver.h b/usr.sbin/nginx/src/core/ngx_resolver.h
index ae34ca56d3a..264c8c42b98 100644
--- a/usr.sbin/nginx/src/core/ngx_resolver.h
+++ b/usr.sbin/nginx/src/core/ngx_resolver.h
@@ -18,6 +18,9 @@
#define NGX_RESOLVE_PTR 12
#define NGX_RESOLVE_MX 15
#define NGX_RESOLVE_TXT 16
+#if (NGX_HAVE_INET6)
+#define NGX_RESOLVE_AAAA 28
+#endif
#define NGX_RESOLVE_DNAME 39
#define NGX_RESOLVE_FORMERR 1
@@ -54,10 +57,18 @@ typedef struct {
/* PTR: resolved name, A: name to resolve */
u_char *name;
+#if (NGX_HAVE_INET6)
+ /* PTR: IPv6 address to resolve (IPv4 address is in rbtree node key) */
+ struct in6_addr addr6;
+#endif
+
u_short nlen;
u_short qlen;
u_char *query;
+#if (NGX_HAVE_INET6)
+ u_char *query6;
+#endif
union {
in_addr_t addr;
@@ -65,11 +76,22 @@ typedef struct {
u_char *cname;
} u;
+ u_char code;
u_short naddrs;
u_short cnlen;
+#if (NGX_HAVE_INET6)
+ union {
+ struct in6_addr addr6;
+ struct in6_addr *addrs6;
+ } u6;
+
+ u_short naddrs6;
+#endif
+
time_t expire;
time_t valid;
+ uint32_t ttl;
ngx_resolver_ctx_t *waiting;
} ngx_resolver_node_t;
@@ -100,6 +122,14 @@ typedef struct {
ngx_queue_t name_expire_queue;
ngx_queue_t addr_expire_queue;
+#if (NGX_HAVE_INET6)
+ ngx_uint_t ipv6; /* unsigned ipv6:1; */
+ ngx_rbtree_t addr6_rbtree;
+ ngx_rbtree_node_t addr6_sentinel;
+ ngx_queue_t addr6_resend_queue;
+ ngx_queue_t addr6_expire_queue;
+#endif
+
time_t resend_timeout;
time_t expire;
time_t valid;
@@ -117,12 +147,12 @@ struct ngx_resolver_ctx_s {
ngx_int_t ident;
ngx_int_t state;
- ngx_int_t type;
ngx_str_t name;
ngx_uint_t naddrs;
- in_addr_t *addrs;
- in_addr_t addr;
+ ngx_addr_t *addrs;
+ ngx_addr_t addr;
+ struct sockaddr_in sin;
ngx_resolver_handler_pt handler;
void *data;
diff --git a/usr.sbin/nginx/src/core/ngx_slab.c b/usr.sbin/nginx/src/core/ngx_slab.c
index ae9d6f3fc0e..be7927ce067 100644
--- a/usr.sbin/nginx/src/core/ngx_slab.c
+++ b/usr.sbin/nginx/src/core/ngx_slab.c
@@ -129,6 +129,7 @@ ngx_slab_init(ngx_slab_pool_t *pool)
pool->pages->slab = pages;
}
+ pool->log_nomem = 1;
pool->log_ctx = &pool->zero;
pool->zero = '\0';
}
@@ -440,7 +441,8 @@ ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p)
n = ((uintptr_t) p & (ngx_pagesize - 1)) >> shift;
m = (uintptr_t) 1 << (n & (sizeof(uintptr_t) * 8 - 1));
n /= (sizeof(uintptr_t) * 8);
- bitmap = (uintptr_t *) ((uintptr_t) p & ~(ngx_pagesize - 1));
+ bitmap = (uintptr_t *)
+ ((uintptr_t) p & ~((uintptr_t) ngx_pagesize - 1));
if (bitmap[n] & m) {
@@ -657,7 +659,10 @@ ngx_slab_alloc_pages(ngx_slab_pool_t *pool, ngx_uint_t pages)
}
}
- ngx_slab_error(pool, NGX_LOG_CRIT, "ngx_slab_alloc() failed: no memory");
+ if (pool->log_nomem) {
+ ngx_slab_error(pool, NGX_LOG_CRIT,
+ "ngx_slab_alloc() failed: no memory");
+ }
return NULL;
}
diff --git a/usr.sbin/nginx/src/core/ngx_slab.h b/usr.sbin/nginx/src/core/ngx_slab.h
index c5e420bfa8e..5735e3bb3b9 100644
--- a/usr.sbin/nginx/src/core/ngx_slab.h
+++ b/usr.sbin/nginx/src/core/ngx_slab.h
@@ -39,6 +39,8 @@ typedef struct {
u_char *log_ctx;
u_char zero;
+ unsigned log_nomem:1;
+
void *data;
void *addr;
} ngx_slab_pool_t;
diff --git a/usr.sbin/nginx/src/core/ngx_string.c b/usr.sbin/nginx/src/core/ngx_string.c
index 1d1989da24d..a4cfcdc7a5e 100644
--- a/usr.sbin/nginx/src/core/ngx_string.c
+++ b/usr.sbin/nginx/src/core/ngx_string.c
@@ -11,6 +11,8 @@
static u_char *ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64,
u_char zero, ngx_uint_t hexadecimal, ngx_uint_t width);
+static void ngx_encode_base64_internal(ngx_str_t *dst, ngx_str_t *src,
+ const u_char *basis, ngx_uint_t padding);
static ngx_int_t ngx_decode_base64_internal(ngx_str_t *dst, ngx_str_t *src,
const u_char *basis);
@@ -486,7 +488,7 @@ ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64, u_char zero,
if (hexadecimal == 0) {
- if (ui64 <= NGX_MAX_UINT32_VALUE) {
+ if (ui64 <= (uint64_t) NGX_MAX_UINT32_VALUE) {
/*
* To divide 64-bit numbers and to find remainders
@@ -853,6 +855,46 @@ ngx_dns_strcmp(u_char *s1, u_char *s2)
ngx_int_t
+ngx_filename_cmp(u_char *s1, u_char *s2, size_t n)
+{
+ ngx_uint_t c1, c2;
+
+ while (n) {
+ c1 = (ngx_uint_t) *s1++;
+ c2 = (ngx_uint_t) *s2++;
+
+#if (NGX_HAVE_CASELESS_FILESYSTEM)
+ c1 = tolower(c1);
+ c2 = tolower(c2);
+#endif
+
+ if (c1 == c2) {
+
+ if (c1) {
+ n--;
+ continue;
+ }
+
+ return 0;
+ }
+
+ /* we need '/' to be the lowest character */
+
+ if (c1 == 0 || c2 == 0) {
+ return c1 - c2;
+ }
+
+ c1 = (c1 == '/') ? 0 : c1;
+ c2 = (c2 == '/') ? 0 : c2;
+
+ return c1 - c2;
+ }
+
+ return 0;
+}
+
+
+ngx_int_t
ngx_atoi(u_char *line, size_t n)
{
ngx_int_t value;
@@ -1060,38 +1102,61 @@ ngx_hex_dump(u_char *dst, u_char *src, size_t len)
void
ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src)
{
- u_char *d, *s;
- size_t len;
static u_char basis64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ ngx_encode_base64_internal(dst, src, basis64, 1);
+}
+
+
+void
+ngx_encode_base64url(ngx_str_t *dst, ngx_str_t *src)
+{
+ static u_char basis64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+ ngx_encode_base64_internal(dst, src, basis64, 0);
+}
+
+
+static void
+ngx_encode_base64_internal(ngx_str_t *dst, ngx_str_t *src, const u_char *basis,
+ ngx_uint_t padding)
+{
+ u_char *d, *s;
+ size_t len;
+
len = src->len;
s = src->data;
d = dst->data;
while (len > 2) {
- *d++ = basis64[(s[0] >> 2) & 0x3f];
- *d++ = basis64[((s[0] & 3) << 4) | (s[1] >> 4)];
- *d++ = basis64[((s[1] & 0x0f) << 2) | (s[2] >> 6)];
- *d++ = basis64[s[2] & 0x3f];
+ *d++ = basis[(s[0] >> 2) & 0x3f];
+ *d++ = basis[((s[0] & 3) << 4) | (s[1] >> 4)];
+ *d++ = basis[((s[1] & 0x0f) << 2) | (s[2] >> 6)];
+ *d++ = basis[s[2] & 0x3f];
s += 3;
len -= 3;
}
if (len) {
- *d++ = basis64[(s[0] >> 2) & 0x3f];
+ *d++ = basis[(s[0] >> 2) & 0x3f];
if (len == 1) {
- *d++ = basis64[(s[0] & 3) << 4];
- *d++ = '=';
+ *d++ = basis[(s[0] & 3) << 4];
+ if (padding) {
+ *d++ = '=';
+ }
} else {
- *d++ = basis64[((s[0] & 3) << 4) | (s[1] >> 4)];
- *d++ = basis64[(s[1] & 0x0f) << 2];
+ *d++ = basis[((s[0] & 3) << 4) | (s[1] >> 4)];
+ *d++ = basis[(s[1] & 0x0f) << 2];
}
- *d++ = '=';
+ if (padding) {
+ *d++ = '=';
+ }
}
dst->len = d - dst->data;
diff --git a/usr.sbin/nginx/src/core/ngx_string.h b/usr.sbin/nginx/src/core/ngx_string.h
index 52c6f338d89..dc0be5b5532 100644
--- a/usr.sbin/nginx/src/core/ngx_string.h
+++ b/usr.sbin/nginx/src/core/ngx_string.h
@@ -167,6 +167,7 @@ ngx_int_t ngx_rstrncmp(u_char *s1, u_char *s2, size_t n);
ngx_int_t ngx_rstrncasecmp(u_char *s1, u_char *s2, size_t n);
ngx_int_t ngx_memn2cmp(u_char *s1, u_char *s2, size_t n1, size_t n2);
ngx_int_t ngx_dns_strcmp(u_char *s1, u_char *s2);
+ngx_int_t ngx_filename_cmp(u_char *s1, u_char *s2, size_t n);
ngx_int_t ngx_atoi(u_char *line, size_t n);
ngx_int_t ngx_atofp(u_char *line, size_t n, size_t point);
@@ -182,6 +183,7 @@ u_char *ngx_hex_dump(u_char *dst, u_char *src, size_t len);
#define ngx_base64_decoded_length(len) (((len + 3) / 4) * 3)
void ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src);
+void ngx_encode_base64url(ngx_str_t *dst, ngx_str_t *src);
ngx_int_t ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src);
ngx_int_t ngx_decode_base64url(ngx_str_t *dst, ngx_str_t *src);
diff --git a/usr.sbin/nginx/src/core/ngx_syslog.c b/usr.sbin/nginx/src/core/ngx_syslog.c
new file mode 100644
index 00000000000..7c5de38b6cb
--- /dev/null
+++ b/usr.sbin/nginx/src/core/ngx_syslog.c
@@ -0,0 +1,342 @@
+
+/*
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+#define NGX_SYSLOG_MAX_STR \
+ NGX_MAX_ERROR_STR + sizeof("<255>Jan 01 00:00:00 ") - 1 \
+ + (NGX_MAXHOSTNAMELEN - 1) + 1 /* space */ \
+ + 32 /* tag */ + 2 /* colon, space */
+
+
+static char *ngx_syslog_parse_args(ngx_conf_t *cf, ngx_syslog_peer_t *peer);
+static ngx_int_t ngx_syslog_init_peer(ngx_syslog_peer_t *peer);
+static void ngx_syslog_cleanup(void *data);
+
+
+static char *facilities[] = {
+ "kern", "user", "mail", "daemon", "auth", "intern", "lpr", "news", "uucp",
+ "clock", "authpriv", "ftp", "ntp", "audit", "alert", "cron", "local0",
+ "local1", "local2", "local3", "local4", "local5", "local6", "local7",
+ NULL
+};
+
+/* note 'error/warn' like in nginx.conf, not 'err/warning' */
+static char *severities[] = {
+ "emerg", "alert", "crit", "error", "warn", "notice", "info", "debug", NULL
+};
+
+static ngx_log_t ngx_syslog_dummy_log;
+static ngx_event_t ngx_syslog_dummy_event;
+
+
+char *
+ngx_syslog_process_conf(ngx_conf_t *cf, ngx_syslog_peer_t *peer)
+{
+ peer->pool = cf->pool;
+ peer->facility = NGX_CONF_UNSET_UINT;
+ peer->severity = NGX_CONF_UNSET_UINT;
+
+ if (ngx_syslog_parse_args(cf, peer) != NGX_CONF_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (peer->server.sockaddr == NULL) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "no syslog server specified");
+ return NGX_CONF_ERROR;
+ }
+
+ if (peer->facility == NGX_CONF_UNSET_UINT) {
+ peer->facility = 23; /* local7 */
+ }
+
+ if (peer->severity == NGX_CONF_UNSET_UINT) {
+ peer->severity = 6; /* info */
+ }
+
+ if (peer->tag.data == NULL) {
+ ngx_str_set(&peer->tag, "nginx");
+ }
+
+ peer->conn.fd = (ngx_socket_t) -1;
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_syslog_parse_args(ngx_conf_t *cf, ngx_syslog_peer_t *peer)
+{
+ u_char *p, *comma, c;
+ size_t len;
+ ngx_str_t *value;
+ ngx_url_t u;
+ ngx_uint_t i;
+
+ value = cf->args->elts;
+
+ p = value[1].data + sizeof("syslog:") - 1;
+
+ for ( ;; ) {
+ comma = (u_char *) ngx_strchr(p, ',');
+
+ if (comma != NULL) {
+ len = comma - p;
+ *comma = '\0';
+
+ } else {
+ len = value[1].data + value[1].len - p;
+ }
+
+ if (ngx_strncmp(p, "server=", 7) == 0) {
+
+ if (peer->server.sockaddr != NULL) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "duplicate syslog \"server\"");
+ return NGX_CONF_ERROR;
+ }
+
+ ngx_memzero(&u, sizeof(ngx_url_t));
+
+ u.url.data = p + 7;
+ u.url.len = len - 7;
+ u.default_port = 514;
+
+ if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
+ if (u.err) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "%s in syslog server \"%V\"",
+ u.err, &u.url);
+ }
+
+ return NGX_CONF_ERROR;
+ }
+
+ peer->server = u.addrs[0];
+
+ } else if (ngx_strncmp(p, "facility=", 9) == 0) {
+
+ if (peer->facility != NGX_CONF_UNSET_UINT) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "duplicate syslog \"facility\"");
+ return NGX_CONF_ERROR;
+ }
+
+ for (i = 0; facilities[i] != NULL; i++) {
+
+ if (ngx_strcmp(p + 9, facilities[i]) == 0) {
+ peer->facility = i;
+ goto next;
+ }
+ }
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "unknown syslog facility \"%s\"", p + 9);
+ return NGX_CONF_ERROR;
+
+ } else if (ngx_strncmp(p, "severity=", 9) == 0) {
+
+ if (peer->severity != NGX_CONF_UNSET_UINT) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "duplicate syslog \"severity\"");
+ return NGX_CONF_ERROR;
+ }
+
+ for (i = 0; severities[i] != NULL; i++) {
+
+ if (ngx_strcmp(p + 9, severities[i]) == 0) {
+ peer->severity = i;
+ goto next;
+ }
+ }
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "unknown syslog severity \"%s\"", p + 9);
+ return NGX_CONF_ERROR;
+
+ } else if (ngx_strncmp(p, "tag=", 4) == 0) {
+
+ if (peer->tag.data != NULL) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "duplicate syslog \"tag\"");
+ return NGX_CONF_ERROR;
+ }
+
+ /*
+ * RFC 3164: the TAG is a string of ABNF alphanumeric characters
+ * that MUST NOT exceed 32 characters.
+ */
+ if (len - 4 > 32) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "syslog tag length exceeds 32");
+ return NGX_CONF_ERROR;
+ }
+
+ for (i = 4; i < len; i++) {
+ c = ngx_tolower(p[i]);
+
+ if (c < '0' || (c > '9' && c < 'a') || c > 'z') {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "syslog \"tag\" only allows "
+ "alphanumeric characters");
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ peer->tag.data = p + 4;
+ peer->tag.len = len - 4;
+
+ } else {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "unknown syslog parameter \"%s\"", p);
+ return NGX_CONF_ERROR;
+ }
+
+ next:
+
+ if (comma == NULL) {
+ break;
+ }
+
+ p = comma + 1;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+u_char *
+ngx_syslog_add_header(ngx_syslog_peer_t *peer, u_char *buf)
+{
+ ngx_uint_t pri;
+
+ pri = peer->facility * 8 + peer->severity;
+
+ return ngx_sprintf(buf, "<%ui>%V %V %V: ", pri, &ngx_cached_syslog_time,
+ &ngx_cycle->hostname, &peer->tag);
+}
+
+
+void
+ngx_syslog_writer(ngx_log_t *log, ngx_uint_t level, u_char *buf,
+ size_t len)
+{
+ u_char *p, msg[NGX_SYSLOG_MAX_STR];
+ ngx_uint_t head_len;
+ ngx_syslog_peer_t *peer;
+
+ peer = log->wdata;
+
+ if (peer->processing) {
+ return;
+ }
+
+ peer->processing = 1;
+ peer->severity = level - 1;
+
+ p = ngx_syslog_add_header(peer, msg);
+ head_len = p - msg;
+
+ len -= NGX_LINEFEED_SIZE;
+
+ if (len > NGX_SYSLOG_MAX_STR - head_len) {
+ len = NGX_SYSLOG_MAX_STR - head_len;
+ }
+
+ p = ngx_snprintf(p, len, "%s", buf);
+
+ (void) ngx_syslog_send(peer, msg, p - msg);
+
+ peer->processing = 0;
+}
+
+
+ssize_t
+ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len)
+{
+ if (peer->conn.fd == (ngx_socket_t) -1) {
+ if (ngx_syslog_init_peer(peer) != NGX_OK) {
+ return NGX_ERROR;
+ }
+ }
+
+ if (ngx_send) {
+ return ngx_send(&peer->conn, buf, len);
+
+ } else {
+ /* event module has not yet set ngx_io */
+ return ngx_os_io.send(&peer->conn, buf, len);
+ }
+}
+
+
+static ngx_int_t
+ngx_syslog_init_peer(ngx_syslog_peer_t *peer)
+{
+ ngx_socket_t fd;
+ ngx_pool_cleanup_t *cln;
+
+ peer->conn.read = &ngx_syslog_dummy_event;
+ peer->conn.write = &ngx_syslog_dummy_event;
+ peer->conn.log = &ngx_syslog_dummy_log;
+
+ ngx_syslog_dummy_event.log = &ngx_syslog_dummy_log;
+
+ fd = ngx_socket(peer->server.sockaddr->sa_family, SOCK_DGRAM, 0);
+ if (fd == (ngx_socket_t) -1) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
+ ngx_socket_n " failed");
+ return NGX_ERROR;
+ }
+
+ if (ngx_nonblocking(fd) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
+ ngx_nonblocking_n " failed");
+ goto failed;
+ }
+
+ if (connect(fd, peer->server.sockaddr, peer->server.socklen) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
+ "connect() failed");
+ goto failed;
+ }
+
+ cln = ngx_pool_cleanup_add(peer->pool, 0);
+ if (cln == NULL) {
+ goto failed;
+ }
+
+ cln->data = peer;
+ cln->handler = ngx_syslog_cleanup;
+
+ peer->conn.fd = fd;
+ return NGX_OK;
+
+failed:
+
+ if (ngx_close_socket(fd) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
+ ngx_close_socket_n " failed");
+ }
+
+ return NGX_ERROR;
+}
+
+
+static void
+ngx_syslog_cleanup(void *data)
+{
+ ngx_syslog_peer_t *peer = data;
+
+ if (ngx_close_socket(peer->conn.fd) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
+ ngx_close_socket_n " failed");
+ }
+}
diff --git a/usr.sbin/nginx/src/core/ngx_syslog.h b/usr.sbin/nginx/src/core/ngx_syslog.h
new file mode 100644
index 00000000000..92d47d5f5fd
--- /dev/null
+++ b/usr.sbin/nginx/src/core/ngx_syslog.h
@@ -0,0 +1,30 @@
+
+/*
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_SYSLOG_H_INCLUDED_
+#define _NGX_SYSLOG_H_INCLUDED_
+
+
+typedef struct {
+ ngx_pool_t *pool;
+ ngx_uint_t facility;
+ ngx_uint_t severity;
+ ngx_str_t tag;
+
+ ngx_addr_t server;
+ ngx_connection_t conn;
+ ngx_uint_t processing; /* unsigned processing:1; */
+} ngx_syslog_peer_t;
+
+
+char *ngx_syslog_process_conf(ngx_conf_t *cf, ngx_syslog_peer_t *peer);
+u_char *ngx_syslog_add_header(ngx_syslog_peer_t *peer, u_char *buf);
+void ngx_syslog_writer(ngx_log_t *log, ngx_uint_t level, u_char *buf,
+ size_t len);
+ssize_t ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len);
+
+
+#endif /* _NGX_SYSLOG_H_INCLUDED_ */
diff --git a/usr.sbin/nginx/src/core/ngx_times.c b/usr.sbin/nginx/src/core/ngx_times.c
index 77490faf045..595c1224d0e 100644
--- a/usr.sbin/nginx/src/core/ngx_times.c
+++ b/usr.sbin/nginx/src/core/ngx_times.c
@@ -29,6 +29,7 @@ volatile ngx_str_t ngx_cached_err_log_time;
volatile ngx_str_t ngx_cached_http_time;
volatile ngx_str_t ngx_cached_http_log_time;
volatile ngx_str_t ngx_cached_http_log_iso8601;
+volatile ngx_str_t ngx_cached_syslog_time;
#if !(NGX_WIN32)
@@ -50,6 +51,8 @@ static u_char cached_http_log_time[NGX_TIME_SLOTS]
[sizeof("28/Sep/1970:12:00:00 +0600")];
static u_char cached_http_log_iso8601[NGX_TIME_SLOTS]
[sizeof("1970-09-28T12:00:00+06:00")];
+static u_char cached_syslog_time[NGX_TIME_SLOTS]
+ [sizeof("Sep 28 12:00:00")];
static char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
@@ -63,6 +66,7 @@ ngx_time_init(void)
ngx_cached_http_time.len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1;
ngx_cached_http_log_time.len = sizeof("28/Sep/1970:12:00:00 +0600") - 1;
ngx_cached_http_log_iso8601.len = sizeof("1970-09-28T12:00:00+06:00") - 1;
+ ngx_cached_syslog_time.len = sizeof("Sep 28 12:00:00") - 1;
ngx_cached_time = &cached_time[0];
@@ -73,7 +77,7 @@ ngx_time_init(void)
void
ngx_time_update(void)
{
- u_char *p0, *p1, *p2, *p3;
+ u_char *p0, *p1, *p2, *p3, *p4;
ngx_tm_t tm, gmt;
time_t sec;
ngx_uint_t msec;
@@ -166,6 +170,11 @@ ngx_time_update(void)
tp->gmtoff < 0 ? '-' : '+',
ngx_abs(tp->gmtoff / 60), ngx_abs(tp->gmtoff % 60));
+ p4 = &cached_syslog_time[slot][0];
+
+ (void) ngx_sprintf(p4, "%s %2d %02d:%02d:%02d",
+ months[tm.ngx_tm_mon - 1], tm.ngx_tm_mday,
+ tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec);
ngx_memory_barrier();
@@ -174,6 +183,7 @@ ngx_time_update(void)
ngx_cached_err_log_time.data = p1;
ngx_cached_http_log_time.data = p2;
ngx_cached_http_log_iso8601.data = p3;
+ ngx_cached_syslog_time.data = p4;
ngx_unlock(&ngx_time_lock);
}
@@ -184,7 +194,7 @@ ngx_time_update(void)
void
ngx_time_sigsafe_update(void)
{
- u_char *p;
+ u_char *p, *p2;
ngx_tm_t tm;
time_t sec;
ngx_time_t *tp;
@@ -224,9 +234,16 @@ ngx_time_sigsafe_update(void)
tm.ngx_tm_mday, tm.ngx_tm_hour,
tm.ngx_tm_min, tm.ngx_tm_sec);
+ p2 = &cached_syslog_time[slot][0];
+
+ (void) ngx_sprintf(p2, "%s %2d %02d:%02d:%02d",
+ months[tm.ngx_tm_mon - 1], tm.ngx_tm_mday,
+ tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec);
+
ngx_memory_barrier();
ngx_cached_err_log_time.data = p;
+ ngx_cached_syslog_time.data = p2;
ngx_unlock(&ngx_time_lock);
}
diff --git a/usr.sbin/nginx/src/core/ngx_times.h b/usr.sbin/nginx/src/core/ngx_times.h
index c4b26a2ed0b..94aedcdc94c 100644
--- a/usr.sbin/nginx/src/core/ngx_times.h
+++ b/usr.sbin/nginx/src/core/ngx_times.h
@@ -40,6 +40,7 @@ extern volatile ngx_str_t ngx_cached_err_log_time;
extern volatile ngx_str_t ngx_cached_http_time;
extern volatile ngx_str_t ngx_cached_http_log_time;
extern volatile ngx_str_t ngx_cached_http_log_iso8601;
+extern volatile ngx_str_t ngx_cached_syslog_time;
/*
* milliseconds elapsed since epoch and truncated to ngx_msec_t,
diff --git a/usr.sbin/nginx/src/event/modules/ngx_devpoll_module.c b/usr.sbin/nginx/src/event/modules/ngx_devpoll_module.c
index 6fdd00233e6..0506103e616 100644
--- a/usr.sbin/nginx/src/event/modules/ngx_devpoll_module.c
+++ b/usr.sbin/nginx/src/event/modules/ngx_devpoll_module.c
@@ -425,7 +425,7 @@ ngx_devpoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
case -1:
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
- "ioctl(DP_ISPOLLED) failed for socket %d, event",
+ "ioctl(DP_ISPOLLED) failed for socket %d, event %04Xd",
fd, revents);
break;
@@ -449,7 +449,7 @@ ngx_devpoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
!= (ssize_t) sizeof(struct pollfd))
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
- "write(/dev/poll) for %d failed, fd");
+ "write(/dev/poll) for %d failed", fd);
}
if (close(fd) == -1) {
diff --git a/usr.sbin/nginx/src/event/modules/ngx_epoll_module.c b/usr.sbin/nginx/src/event/modules/ngx_epoll_module.c
index ee77d8e4aff..f5f66317943 100644
--- a/usr.sbin/nginx/src/event/modules/ngx_epoll_module.c
+++ b/usr.sbin/nginx/src/event/modules/ngx_epoll_module.c
@@ -25,6 +25,8 @@
#define EPOLLERR 0x008
#define EPOLLHUP 0x010
+#define EPOLLRDHUP 0x2000
+
#define EPOLLET 0x80000000
#define EPOLLONESHOT 0x40000000
@@ -396,13 +398,13 @@ ngx_epoll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
if (event == NGX_READ_EVENT) {
e = c->write;
prev = EPOLLOUT;
-#if (NGX_READ_EVENT != EPOLLIN)
- events = EPOLLIN;
+#if (NGX_READ_EVENT != EPOLLIN|EPOLLRDHUP)
+ events = EPOLLIN|EPOLLRDHUP;
#endif
} else {
e = c->read;
- prev = EPOLLIN;
+ prev = EPOLLIN|EPOLLRDHUP;
#if (NGX_WRITE_EVENT != EPOLLOUT)
events = EPOLLOUT;
#endif
@@ -466,7 +468,7 @@ ngx_epoll_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
} else {
e = c->read;
- prev = EPOLLIN;
+ prev = EPOLLIN|EPOLLRDHUP;
}
if (e->active) {
@@ -501,7 +503,7 @@ ngx_epoll_add_connection(ngx_connection_t *c)
{
struct epoll_event ee;
- ee.events = EPOLLIN|EPOLLOUT|EPOLLET;
+ ee.events = EPOLLIN|EPOLLOUT|EPOLLET|EPOLLRDHUP;
ee.data.ptr = (void *) ((uintptr_t) c | c->read->instance);
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
@@ -666,6 +668,12 @@ ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
if ((revents & EPOLLIN) && rev->active) {
+#if (NGX_HAVE_EPOLLRDHUP)
+ if (revents & EPOLLRDHUP) {
+ rev->pending_eof = 1;
+ }
+#endif
+
if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) {
rev->posted_ready = 1;
diff --git a/usr.sbin/nginx/src/event/modules/ngx_select_module.c b/usr.sbin/nginx/src/event/modules/ngx_select_module.c
index ed71368e985..51690558e91 100644
--- a/usr.sbin/nginx/src/event/modules/ngx_select_module.c
+++ b/usr.sbin/nginx/src/event/modules/ngx_select_module.c
@@ -288,7 +288,7 @@ ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
ngx_log_error(level, cycle->log, err, "select() failed");
- if (err == EBADF) {
+ if (err == NGX_EBADF) {
ngx_select_repair_fd_sets(cycle);
}
diff --git a/usr.sbin/nginx/src/event/modules/ngx_win32_select_module.c b/usr.sbin/nginx/src/event/modules/ngx_win32_select_module.c
index 0a02ffca0b0..eb5382d4e0b 100644
--- a/usr.sbin/nginx/src/event/modules/ngx_win32_select_module.c
+++ b/usr.sbin/nginx/src/event/modules/ngx_win32_select_module.c
@@ -148,8 +148,8 @@ ngx_select_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
return NGX_ERROR;
}
- if ((event == NGX_READ_EVENT) && (max_read >= FD_SETSIZE)
- || (event == NGX_WRITE_EVENT) && (max_write >= FD_SETSIZE))
+ if ((event == NGX_READ_EVENT && max_read >= FD_SETSIZE)
+ || (event == NGX_WRITE_EVENT && max_write >= FD_SETSIZE))
{
ngx_log_error(NGX_LOG_ERR, ev->log, 0,
"maximum number of descriptors "
diff --git a/usr.sbin/nginx/src/event/ngx_event.c b/usr.sbin/nginx/src/event/ngx_event.c
index c4c61204b78..e2857f0c05c 100644
--- a/usr.sbin/nginx/src/event/ngx_event.c
+++ b/usr.sbin/nginx/src/event/ngx_event.c
@@ -56,7 +56,6 @@ ngx_uint_t ngx_accept_events;
ngx_uint_t ngx_accept_mutex_held;
ngx_msec_t ngx_accept_mutex_delay;
ngx_int_t ngx_accept_disabled;
-ngx_file_t ngx_accept_mutex_lock_file;
#if (NGX_STAT_STUB)
diff --git a/usr.sbin/nginx/src/event/ngx_event.h b/usr.sbin/nginx/src/event/ngx_event.h
index 93c457c7b9a..530c9486c51 100644
--- a/usr.sbin/nginx/src/event/ngx_event.h
+++ b/usr.sbin/nginx/src/event/ngx_event.h
@@ -69,13 +69,9 @@ struct ngx_event_s {
unsigned delayed:1;
- unsigned read_discarded:1;
-
- unsigned unexpected_eof:1;
-
unsigned deferred_accept:1;
- /* the pending eof reported by kqueue or in aio chain operation */
+ /* the pending eof reported by kqueue, epoll or in aio chain operation */
unsigned pending_eof:1;
#if !(NGX_THREADS)
@@ -353,6 +349,11 @@ extern ngx_event_actions_t ngx_event_actions;
#define NGX_VNODE_EVENT 0
+#if (NGX_HAVE_EPOLL) && !(NGX_HAVE_EPOLLRDHUP)
+#define EPOLLRDHUP 0
+#endif
+
+
#if (NGX_HAVE_KQUEUE)
#define NGX_READ_EVENT EVFILT_READ
@@ -396,7 +397,7 @@ extern ngx_event_actions_t ngx_event_actions;
#elif (NGX_HAVE_EPOLL)
-#define NGX_READ_EVENT EPOLLIN
+#define NGX_READ_EVENT (EPOLLIN|EPOLLRDHUP)
#define NGX_WRITE_EVENT EPOLLOUT
#define NGX_LEVEL_EVENT 0
diff --git a/usr.sbin/nginx/src/event/ngx_event_accept.c b/usr.sbin/nginx/src/event/ngx_event_accept.c
index 6087d60daaf..bf67ecee062 100644
--- a/usr.sbin/nginx/src/event/ngx_event_accept.c
+++ b/usr.sbin/nginx/src/event/ngx_event_accept.c
@@ -70,7 +70,7 @@ ngx_event_accept(ngx_event_t *ev)
s = accept(lc->fd, (struct sockaddr *) sa, &socklen);
#endif
- if (s == -1) {
+ if (s == (ngx_socket_t) -1) {
err = ngx_socket_errno;
if (err == NGX_EAGAIN) {
@@ -212,6 +212,7 @@ ngx_event_accept(ngx_event_t *ev)
c->socklen = socklen;
c->listening = ls;
c->local_sockaddr = ls->sockaddr;
+ c->local_socklen = ls->socklen;
c->unexpected_eof = 1;
@@ -275,7 +276,8 @@ ngx_event_accept(ngx_event_t *ev)
return;
}
- c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->addr_text.data,
+ c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->socklen,
+ c->addr_text.data,
ls->addr_text_max_len, 0);
if (c->addr_text.len == 0) {
ngx_close_accepted_connection(c);
@@ -296,7 +298,7 @@ ngx_event_accept(ngx_event_t *ev)
cidr = ecf->debug_connection.elts;
for (i = 0; i < ecf->debug_connection.nelts; i++) {
- if (cidr[i].family != c->sockaddr->sa_family) {
+ if (cidr[i].family != (ngx_uint_t) c->sockaddr->sa_family) {
goto next;
}
@@ -342,7 +344,7 @@ ngx_event_accept(ngx_event_t *ev)
#endif
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, log, 0,
- "*%d accept: %V fd:%d", c->number, &c->addr_text, s);
+ "*%uA accept: %V fd:%d", c->number, &c->addr_text, s);
if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) {
if (ngx_add_conn(c) == NGX_ERROR) {
diff --git a/usr.sbin/nginx/src/event/ngx_event_connect.c b/usr.sbin/nginx/src/event/ngx_event_connect.c
index e6ae6564e6c..5fcabcfd1fa 100644
--- a/usr.sbin/nginx/src/event/ngx_event_connect.c
+++ b/usr.sbin/nginx/src/event/ngx_event_connect.c
@@ -31,7 +31,7 @@ ngx_event_connect_peer(ngx_peer_connection_t *pc)
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, 0, "socket %d", s);
- if (s == -1) {
+ if (s == (ngx_socket_t) -1) {
ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
ngx_socket_n " failed");
return NGX_ERROR;
@@ -122,7 +122,7 @@ ngx_event_connect_peer(ngx_peer_connection_t *pc)
}
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pc->log, 0,
- "connect to %V, fd:%d #%d", pc->name, s, c->number);
+ "connect to %V, fd:%d #%uA", pc->name, s, c->number);
rc = connect(s, pc->sockaddr, pc->socklen);
diff --git a/usr.sbin/nginx/src/event/ngx_event_openssl.c b/usr.sbin/nginx/src/event/ngx_event_openssl.c
index 81a1e42d81c..6290a57fe0c 100644
--- a/usr.sbin/nginx/src/event/ngx_event_openssl.c
+++ b/usr.sbin/nginx/src/event/ngx_event_openssl.c
@@ -15,7 +15,7 @@ typedef struct {
} ngx_openssl_conf_t;
-static int ngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store);
+static int ngx_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store);
static void ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where,
int ret);
static void ngx_ssl_handshake_handler(ngx_event_t *ev);
@@ -38,6 +38,12 @@ static void ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache,
static void ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp,
ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
+#ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
+static int ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn,
+ unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx,
+ HMAC_CTX *hctx, int enc);
+#endif
+
static void *ngx_openssl_create_conf(ngx_cycle_t *cycle);
static char *ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static void ngx_openssl_exit(ngx_cycle_t *cycle);
@@ -82,6 +88,7 @@ ngx_module_t ngx_openssl_module = {
int ngx_ssl_connection_index;
int ngx_ssl_server_conf_index;
int ngx_ssl_session_cache_index;
+int ngx_ssl_session_ticket_keys_index;
int ngx_ssl_certificate_index;
int ngx_ssl_stapling_index;
@@ -139,6 +146,14 @@ ngx_ssl_init(ngx_log_t *log)
return NGX_ERROR;
}
+ ngx_ssl_session_ticket_keys_index = SSL_CTX_get_ex_new_index(0, NULL, NULL,
+ NULL, NULL);
+ if (ngx_ssl_session_ticket_keys_index == -1) {
+ ngx_ssl_error(NGX_LOG_ALERT, log, 0,
+ "SSL_CTX_get_ex_new_index() failed");
+ return NGX_ERROR;
+ }
+
ngx_ssl_certificate_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
NULL);
if (ngx_ssl_certificate_index == -1) {
@@ -175,6 +190,8 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data)
return NGX_ERROR;
}
+ ssl->buffer_size = NGX_SSL_BUFSIZE;
+
/* client side options */
SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_SESS_ID_BUG);
@@ -185,8 +202,10 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data)
SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG);
SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER);
+#ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING
/* this option allow a potential SSL 2.0 rollback (CAN-2005-2969) */
SSL_CTX_set_options(ssl->ctx, SSL_OP_MSIE_SSLV2_RSA_PADDING);
+#endif
SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLEAY_080_CLIENT_DH_BUG);
SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_D5_BUG);
@@ -276,6 +295,8 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
{
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"SSL_CTX_set_ex_data() failed");
+ X509_free(x509);
+ BIO_free(bio);
return NGX_ERROR;
}
@@ -340,7 +361,7 @@ ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
{
STACK_OF(X509_NAME) *list;
- SSL_CTX_set_verify(ssl->ctx, SSL_VERIFY_PEER, ngx_http_ssl_verify_callback);
+ SSL_CTX_set_verify(ssl->ctx, SSL_VERIFY_PEER, ngx_ssl_verify_callback);
SSL_CTX_set_verify_depth(ssl->ctx, depth);
@@ -361,6 +382,13 @@ ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
return NGX_ERROR;
}
+ /*
+ * SSL_CTX_load_verify_locations() may leave errors in the error queue
+ * while returning success
+ */
+
+ ERR_clear_error();
+
list = SSL_load_client_CA_file((char *) cert->data);
if (list == NULL) {
@@ -405,6 +433,13 @@ ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
return NGX_ERROR;
}
+ /*
+ * SSL_CTX_load_verify_locations() may leave errors in the error queue
+ * while returning success
+ */
+
+ ERR_clear_error();
+
return NGX_OK;
}
@@ -455,7 +490,7 @@ ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl)
static int
-ngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store)
+ngx_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store)
{
#if (NGX_DEBUG)
char *subject, *issuer;
@@ -501,6 +536,7 @@ ngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store)
static void
ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret)
{
+ BIO *rbio, *wbio;
ngx_connection_t *c;
if (where & SSL_CB_HANDSHAKE_START) {
@@ -511,11 +547,37 @@ ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret)
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL renegotiation");
}
}
+
+ if ((where & SSL_CB_ACCEPT_LOOP) == SSL_CB_ACCEPT_LOOP) {
+ c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
+
+ if (!c->ssl->handshake_buffer_set) {
+ /*
+ * By default OpenSSL uses 4k buffer during a handshake,
+ * which is too low for long certificate chains and might
+ * result in extra round-trips.
+ *
+ * To adjust a buffer size we detect that buffering was added
+ * to write side of the connection by comparing rbio and wbio.
+ * If they are different, we assume that it's due to buffering
+ * added to wbio, and set buffer size.
+ */
+
+ rbio = SSL_get_rbio((ngx_ssl_conn_t *) ssl_conn);
+ wbio = SSL_get_wbio((ngx_ssl_conn_t *) ssl_conn);
+
+ if (rbio != wbio) {
+ (void) BIO_set_write_buffer_size(wbio, NGX_SSL_BUFSIZE);
+ c->ssl->handshake_buffer_set = 1;
+ }
+ }
+ }
}
RSA *
-ngx_ssl_rsa512_key_callback(SSL *ssl, int is_export, int key_length)
+ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export,
+ int key_length)
{
static RSA *key;
@@ -664,6 +726,7 @@ ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags)
}
sc->buffer = ((flags & NGX_SSL_BUFFER) != 0);
+ sc->buffer_size = ssl->buffer_size;
sc->connection = SSL_new(ssl->ctx);
@@ -1160,7 +1223,7 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
buf = c->ssl->buf;
if (buf == NULL) {
- buf = ngx_create_temp_buf(c->pool, NGX_SSL_BUFSIZE);
+ buf = ngx_create_temp_buf(c->pool, c->ssl->buffer_size);
if (buf == NULL) {
return NGX_CHAIN_ERROR;
}
@@ -1169,14 +1232,14 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
}
if (buf->start == NULL) {
- buf->start = ngx_palloc(c->pool, NGX_SSL_BUFSIZE);
+ buf->start = ngx_palloc(c->pool, c->ssl->buffer_size);
if (buf->start == NULL) {
return NGX_CHAIN_ERROR;
}
buf->pos = buf->start;
buf->last = buf->start;
- buf->end = buf->start + NGX_SSL_BUFSIZE;
+ buf->end = buf->start + c->ssl->buffer_size;
}
send = buf->last - buf->pos;
@@ -1662,6 +1725,8 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
{
long cache_mode;
+ SSL_CTX_set_timeout(ssl->ctx, (long) timeout);
+
if (builtin_session_cache == NGX_SSL_NO_SCACHE) {
SSL_CTX_set_session_cache_mode(ssl->ctx, SSL_SESS_CACHE_OFF);
return NGX_OK;
@@ -1707,8 +1772,6 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
}
}
- SSL_CTX_set_timeout(ssl->ctx, (long) timeout);
-
if (shm_zone) {
SSL_CTX_sess_set_new_cb(ssl->ctx, ngx_ssl_new_session);
SSL_CTX_sess_set_get_cb(ssl->ctx, ngx_ssl_get_cached_session);
@@ -1739,13 +1802,13 @@ ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data)
return NGX_OK;
}
+ shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
+
if (shm_zone->shm.exists) {
- shm_zone->data = data;
+ shm_zone->data = shpool->data;
return NGX_OK;
}
- shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
-
cache = ngx_slab_alloc(shpool, sizeof(ngx_ssl_session_cache_t));
if (cache == NULL) {
return NGX_ERROR;
@@ -1769,6 +1832,8 @@ ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data)
ngx_sprintf(shpool->log_ctx, " in SSL session shared cache \"%V\"%Z",
&shm_zone->shm.name);
+ shpool->log_nomem = 0;
+
return NGX_OK;
}
@@ -1921,7 +1986,7 @@ failed:
ngx_shmtx_unlock(&shpool->mutex);
ngx_log_error(NGX_LOG_ALERT, c->log, 0,
- "could not add new SSL session to the session cache");
+ "could not allocate new session%s", shpool->log_ctx);
return 0;
}
@@ -2198,6 +2263,218 @@ ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp,
}
+#ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
+
+ngx_int_t
+ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths)
+{
+ u_char buf[48];
+ ssize_t n;
+ ngx_str_t *path;
+ ngx_file_t file;
+ ngx_uint_t i;
+ ngx_array_t *keys;
+ ngx_file_info_t fi;
+ ngx_ssl_session_ticket_key_t *key;
+
+ if (paths == NULL) {
+ return NGX_OK;
+ }
+
+ keys = ngx_array_create(cf->pool, paths->nelts,
+ sizeof(ngx_ssl_session_ticket_key_t));
+ if (keys == NULL) {
+ return NGX_ERROR;
+ }
+
+ path = paths->elts;
+ for (i = 0; i < paths->nelts; i++) {
+
+ if (ngx_conf_full_name(cf->cycle, &path[i], 1) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ ngx_memzero(&file, sizeof(ngx_file_t));
+ file.name = path[i];
+ file.log = cf->log;
+
+ file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY, 0, 0);
+ if (file.fd == NGX_INVALID_FILE) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
+ ngx_open_file_n " \"%V\" failed", &file.name);
+ return NGX_ERROR;
+ }
+
+ if (ngx_fd_info(file.fd, &fi) == NGX_FILE_ERROR) {
+ ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno,
+ ngx_fd_info_n " \"%V\" failed", &file.name);
+ goto failed;
+ }
+
+ if (ngx_file_size(&fi) != 48) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"%V\" must be 48 bytes", &file.name);
+ goto failed;
+ }
+
+ n = ngx_read_file(&file, buf, 48, 0);
+
+ if (n == NGX_ERROR) {
+ ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno,
+ ngx_read_file_n " \"%V\" failed", &file.name);
+ goto failed;
+ }
+
+ if (n != 48) {
+ ngx_conf_log_error(NGX_LOG_CRIT, cf, 0,
+ ngx_read_file_n " \"%V\" returned only "
+ "%z bytes instead of 48", &file.name, n);
+ goto failed;
+ }
+
+ key = ngx_array_push(keys);
+ if (key == NULL) {
+ goto failed;
+ }
+
+ ngx_memcpy(key->name, buf, 16);
+ ngx_memcpy(key->aes_key, buf + 16, 16);
+ ngx_memcpy(key->hmac_key, buf + 32, 16);
+
+ if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
+ ngx_close_file_n " \"%V\" failed", &file.name);
+ }
+ }
+
+ if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_session_ticket_keys_index, keys)
+ == 0)
+ {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "SSL_CTX_set_ex_data() failed");
+ return NGX_ERROR;
+ }
+
+ if (SSL_CTX_set_tlsext_ticket_key_cb(ssl->ctx,
+ ngx_ssl_session_ticket_key_callback)
+ == 0)
+ {
+ ngx_log_error(NGX_LOG_WARN, cf->log, 0,
+ "nginx was built with Session Tickets support, however, "
+ "now it is linked dynamically to an OpenSSL library "
+ "which has no tlsext support, therefore Session Tickets "
+ "are not available");
+ }
+
+ return NGX_OK;
+
+failed:
+
+ if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
+ ngx_close_file_n " \"%V\" failed", &file.name);
+ }
+
+ return NGX_ERROR;
+}
+
+
+#ifdef OPENSSL_NO_SHA256
+#define ngx_ssl_session_ticket_md EVP_sha1
+#else
+#define ngx_ssl_session_ticket_md EVP_sha256
+#endif
+
+
+static int
+ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn,
+ unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx,
+ HMAC_CTX *hctx, int enc)
+{
+ SSL_CTX *ssl_ctx;
+ ngx_uint_t i;
+ ngx_array_t *keys;
+ ngx_ssl_session_ticket_key_t *key;
+#if (NGX_DEBUG)
+ u_char buf[32];
+ ngx_connection_t *c;
+#endif
+
+ ssl_ctx = SSL_get_SSL_CTX(ssl_conn);
+
+ keys = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_session_ticket_keys_index);
+ if (keys == NULL) {
+ return -1;
+ }
+
+ key = keys->elts;
+
+#if (NGX_DEBUG)
+ c = ngx_ssl_get_connection(ssl_conn);
+#endif
+
+ if (enc == 1) {
+ /* encrypt session ticket */
+
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
+ "ssl session ticket encrypt, key: \"%*s\" (%s session)",
+ ngx_hex_dump(buf, key[0].name, 16) - buf, buf,
+ SSL_session_reused(ssl_conn) ? "reused" : "new");
+
+ RAND_pseudo_bytes(iv, 16);
+ EVP_EncryptInit_ex(ectx, EVP_aes_128_cbc(), NULL, key[0].aes_key, iv);
+ HMAC_Init_ex(hctx, key[0].hmac_key, 16,
+ ngx_ssl_session_ticket_md(), NULL);
+ memcpy(name, key[0].name, 16);
+
+ return 0;
+
+ } else {
+ /* decrypt session ticket */
+
+ for (i = 0; i < keys->nelts; i++) {
+ if (ngx_memcmp(name, key[i].name, 16) == 0) {
+ goto found;
+ }
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
+ "ssl session ticket decrypt, key: \"%*s\" not found",
+ ngx_hex_dump(buf, name, 16) - buf, buf);
+
+ return 0;
+
+ found:
+
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
+ "ssl session ticket decrypt, key: \"%*s\"%s",
+ ngx_hex_dump(buf, key[i].name, 16) - buf, buf,
+ (i == 0) ? " (default)" : "");
+
+ HMAC_Init_ex(hctx, key[i].hmac_key, 16,
+ ngx_ssl_session_ticket_md(), NULL);
+ EVP_DecryptInit_ex(ectx, EVP_aes_128_cbc(), NULL, key[i].aes_key, iv);
+
+ return (i == 0) ? 1 : 2 /* renew */;
+ }
+}
+
+#else
+
+ngx_int_t
+ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths)
+{
+ if (paths) {
+ ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
+ "\"ssl_session_ticket_keys\" ignored, not supported");
+ }
+
+ return NGX_OK;
+}
+
+#endif
+
+
void
ngx_ssl_cleanup_ctx(void *data)
{
@@ -2252,6 +2529,20 @@ ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
ngx_int_t
+ngx_ssl_get_session_reused(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
+{
+ if (SSL_session_reused(c->ssl->connection)) {
+ ngx_str_set(s, "r");
+
+ } else {
+ ngx_str_set(s, ".");
+ }
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
{
size_t len;
diff --git a/usr.sbin/nginx/src/event/ngx_event_openssl.h b/usr.sbin/nginx/src/event/ngx_event_openssl.h
index bf81d2529c9..b7f85001948 100644
--- a/usr.sbin/nginx/src/event/ngx_event_openssl.h
+++ b/usr.sbin/nginx/src/event/ngx_event_openssl.h
@@ -29,6 +29,7 @@
typedef struct {
SSL_CTX *ctx;
ngx_log_t *log;
+ size_t buffer_size;
} ngx_ssl_t;
@@ -37,6 +38,7 @@ typedef struct {
ngx_int_t last;
ngx_buf_t *buf;
+ size_t buffer_size;
ngx_connection_handler_pt handler;
@@ -48,6 +50,7 @@ typedef struct {
unsigned buffer:1;
unsigned no_wait_shutdown:1;
unsigned no_send_shutdown:1;
+ unsigned handshake_buffer_set:1;
} ngx_ssl_connection_t;
@@ -82,6 +85,16 @@ typedef struct {
} ngx_ssl_session_cache_t;
+#ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
+
+typedef struct {
+ u_char name[16];
+ u_char aes_key[16];
+ u_char hmac_key[16];
+} ngx_ssl_session_ticket_key_t;
+
+#endif
+
#define NGX_SSL_SSLv2 0x0002
#define NGX_SSL_SSLv3 0x0004
@@ -109,11 +122,14 @@ ngx_int_t ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_str_t *file, ngx_str_t *responder, ngx_uint_t verify);
ngx_int_t ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_resolver_t *resolver, ngx_msec_t resolver_timeout);
-RSA *ngx_ssl_rsa512_key_callback(SSL *ssl, int is_export, int key_length);
+RSA *ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export,
+ int key_length);
ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file);
ngx_int_t ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name);
ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t timeout);
+ngx_int_t ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl,
+ ngx_array_t *paths);
ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data);
ngx_int_t ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c,
ngx_uint_t flags);
@@ -141,6 +157,8 @@ ngx_int_t ngx_ssl_get_cipher_name(ngx_connection_t *c, ngx_pool_t *pool,
ngx_str_t *s);
ngx_int_t ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool,
ngx_str_t *s);
+ngx_int_t ngx_ssl_get_session_reused(ngx_connection_t *c, ngx_pool_t *pool,
+ ngx_str_t *s);
ngx_int_t ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool,
ngx_str_t *s);
ngx_int_t ngx_ssl_get_certificate(ngx_connection_t *c, ngx_pool_t *pool,
@@ -171,6 +189,7 @@ void ngx_ssl_cleanup_ctx(void *data);
extern int ngx_ssl_connection_index;
extern int ngx_ssl_server_conf_index;
extern int ngx_ssl_session_cache_index;
+extern int ngx_ssl_session_ticket_keys_index;
extern int ngx_ssl_certificate_index;
extern int ngx_ssl_stapling_index;
diff --git a/usr.sbin/nginx/src/event/ngx_event_openssl_stapling.c b/usr.sbin/nginx/src/event/ngx_event_openssl_stapling.c
index 77baeb98f1f..3a3cc7f9e03 100644
--- a/usr.sbin/nginx/src/event/ngx_event_openssl_stapling.c
+++ b/usr.sbin/nginx/src/event/ngx_event_openssl_stapling.c
@@ -792,7 +792,6 @@ ngx_ssl_ocsp_request(ngx_ssl_ocsp_ctx_t *ctx)
}
resolve->name = ctx->host;
- resolve->type = NGX_RESOLVE_A;
resolve->handler = ngx_ssl_ocsp_resolve_handler;
resolve->data = ctx;
resolve->timeout = ctx->resolver_timeout;
@@ -816,13 +815,14 @@ ngx_ssl_ocsp_resolve_handler(ngx_resolver_ctx_t *resolve)
{
ngx_ssl_ocsp_ctx_t *ctx = resolve->data;
- u_char *p;
- size_t len;
- in_port_t port;
- ngx_uint_t i;
- struct sockaddr_in *sin;
+ u_char *p;
+ size_t len;
+ in_port_t port;
+ socklen_t socklen;
+ ngx_uint_t i;
+ struct sockaddr *sockaddr;
- ngx_log_debug0(NGX_LOG_ALERT, ctx->log, 0,
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
"ssl ocsp resolve handler");
if (resolve->state) {
@@ -835,15 +835,19 @@ ngx_ssl_ocsp_resolve_handler(ngx_resolver_ctx_t *resolve)
#if (NGX_DEBUG)
{
- in_addr_t addr;
+ u_char text[NGX_SOCKADDR_STRLEN];
+ ngx_str_t addr;
+
+ addr.data = text;
for (i = 0; i < resolve->naddrs; i++) {
- addr = ntohl(resolve->addrs[i]);
+ addr.len = ngx_sock_ntop(resolve->addrs[i].sockaddr,
+ resolve->addrs[i].socklen,
+ text, NGX_SOCKADDR_STRLEN, 0);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
+ "name was resolved to %V", &addr);
- ngx_log_debug4(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
- "name was resolved to %ud.%ud.%ud.%ud",
- (addr >> 24) & 0xff, (addr >> 16) & 0xff,
- (addr >> 8) & 0xff, addr & 0xff);
}
}
#endif
@@ -859,26 +863,34 @@ ngx_ssl_ocsp_resolve_handler(ngx_resolver_ctx_t *resolve)
for (i = 0; i < resolve->naddrs; i++) {
- sin = ngx_pcalloc(ctx->pool, sizeof(struct sockaddr_in));
- if (sin == NULL) {
+ socklen = resolve->addrs[i].socklen;
+
+ sockaddr = ngx_palloc(ctx->pool, socklen);
+ if (sockaddr == NULL) {
goto failed;
}
- sin->sin_family = AF_INET;
- sin->sin_port = port;
- sin->sin_addr.s_addr = resolve->addrs[i];
+ ngx_memcpy(sockaddr, resolve->addrs[i].sockaddr, socklen);
- ctx->addrs[i].sockaddr = (struct sockaddr *) sin;
- ctx->addrs[i].socklen = sizeof(struct sockaddr_in);
+ switch (sockaddr->sa_family) {
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ ((struct sockaddr_in6 *) sockaddr)->sin6_port = port;
+ break;
+#endif
+ default: /* AF_INET */
+ ((struct sockaddr_in *) sockaddr)->sin_port = port;
+ }
- len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1;
+ ctx->addrs[i].sockaddr = sockaddr;
+ ctx->addrs[i].socklen = socklen;
- p = ngx_pnalloc(ctx->pool, len);
+ p = ngx_pnalloc(ctx->pool, NGX_SOCKADDR_STRLEN);
if (p == NULL) {
goto failed;
}
- len = ngx_sock_ntop((struct sockaddr *) sin, p, len, 1);
+ len = ngx_sock_ntop(sockaddr, socklen, p, NGX_SOCKADDR_STRLEN, 1);
ctx->addrs[i].name.len = len;
ctx->addrs[i].name.data = p;
diff --git a/usr.sbin/nginx/src/event/ngx_event_pipe.c b/usr.sbin/nginx/src/event/ngx_event_pipe.c
index 476d56e30e3..eed807d61b8 100644
--- a/usr.sbin/nginx/src/event/ngx_event_pipe.c
+++ b/usr.sbin/nginx/src/event/ngx_event_pipe.c
@@ -57,7 +57,7 @@ ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write)
do_write = 1;
}
- if (p->upstream->fd != -1) {
+ if (p->upstream->fd != (ngx_socket_t) -1) {
rev = p->upstream->read;
flags = (rev->eof || rev->error) ? NGX_CLOSE_EVENT : 0;
@@ -74,7 +74,9 @@ ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write)
}
}
- if (p->downstream->fd != -1 && p->downstream->data == p->output_ctx) {
+ if (p->downstream->fd != (ngx_socket_t) -1
+ && p->downstream->data == p->output_ctx)
+ {
wev = p->downstream->write;
if (ngx_handle_write_event(wev, p->send_lowat) != NGX_OK) {
return NGX_ABORT;
@@ -220,8 +222,8 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p)
{
/*
- * if it is allowed, then save some bufs from r->in
- * to a temporary file, and add them to a r->out chain
+ * if it is allowed, then save some bufs from p->in
+ * to a temporary file, and add them to a p->out chain
*/
rc = ngx_event_pipe_write_chain_to_temp_file(p);
@@ -454,7 +456,7 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p)
size_t bsize;
ngx_int_t rc;
ngx_uint_t flush, flushed, prev_last_shadow;
- ngx_chain_t *out, **ll, *cl, file;
+ ngx_chain_t *out, **ll, *cl;
ngx_connection_t *downstream;
downstream = p->downstream;
@@ -514,13 +516,10 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p)
}
if (p->cacheable && p->buf_to_file) {
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0,
+ "pipe write chain");
- file.buf = p->buf_to_file;
- file.next = NULL;
-
- if (ngx_write_chain_to_temp_file(p->temp_file, &file)
- == NGX_ERROR)
- {
+ if (ngx_event_pipe_write_chain_to_temp_file(p) == NGX_ABORT) {
return NGX_ABORT;
}
}
@@ -858,19 +857,13 @@ ngx_event_pipe_copy_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
return NGX_OK;
}
- if (p->free) {
- cl = p->free;
- b = cl->buf;
- p->free = cl->next;
- ngx_free_chain(p->pool, cl);
-
- } else {
- b = ngx_alloc_buf(p->pool);
- if (b == NULL) {
- return NGX_ERROR;
- }
+ cl = ngx_chain_get_free_buf(p->pool, &p->free);
+ if (cl == NULL) {
+ return NGX_ERROR;
}
+ b = cl->buf;
+
ngx_memcpy(b, buf, sizeof(ngx_buf_t));
b->shadow = buf;
b->tag = p->tag;
@@ -878,14 +871,6 @@ ngx_event_pipe_copy_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
b->recycled = 1;
buf->shadow = b;
- cl = ngx_alloc_chain_link(p->pool);
- if (cl == NULL) {
- return NGX_ERROR;
- }
-
- cl->buf = b;
- cl->next = NULL;
-
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num);
if (p->in) {
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_access_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_access_module.c
index 70a4262fccb..c553e46106b 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_access_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_access_module.c
@@ -26,11 +26,22 @@ typedef struct {
#endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+typedef struct {
+ ngx_uint_t deny; /* unsigned deny:1; */
+} ngx_http_access_rule_un_t;
+
+#endif
+
typedef struct {
ngx_array_t *rules; /* array of ngx_http_access_rule_t */
#if (NGX_HAVE_INET6)
ngx_array_t *rules6; /* array of ngx_http_access_rule6_t */
#endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+ ngx_array_t *rules_un; /* array of ngx_http_access_rule_un_t */
+#endif
} ngx_http_access_loc_conf_t;
@@ -41,6 +52,10 @@ static ngx_int_t ngx_http_access_inet(ngx_http_request_t *r,
static ngx_int_t ngx_http_access_inet6(ngx_http_request_t *r,
ngx_http_access_loc_conf_t *alcf, u_char *p);
#endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+static ngx_int_t ngx_http_access_unix(ngx_http_request_t *r,
+ ngx_http_access_loc_conf_t *alcf);
+#endif
static ngx_int_t ngx_http_access_found(ngx_http_request_t *r, ngx_uint_t deny);
static char *ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
@@ -144,6 +159,19 @@ ngx_http_access_handler(ngx_http_request_t *r)
return ngx_http_access_inet6(r, alcf, p);
}
+ break;
+
+#endif
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+ case AF_UNIX:
+ if (alcf->rules_un) {
+ return ngx_http_access_unix(r, alcf);
+ }
+
+ break;
+
#endif
}
@@ -221,6 +249,29 @@ ngx_http_access_inet6(ngx_http_request_t *r, ngx_http_access_loc_conf_t *alcf,
#endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+static ngx_int_t
+ngx_http_access_unix(ngx_http_request_t *r, ngx_http_access_loc_conf_t *alcf)
+{
+ ngx_uint_t i;
+ ngx_http_access_rule_un_t *rule_un;
+
+ rule_un = alcf->rules_un->elts;
+ for (i = 0; i < alcf->rules_un->nelts; i++) {
+
+ /* TODO: check path */
+ if (1) {
+ return ngx_http_access_found(r, rule_un[i].deny);
+ }
+ }
+
+ return NGX_DECLINED;
+}
+
+#endif
+
+
static ngx_int_t
ngx_http_access_found(ngx_http_request_t *r, ngx_uint_t deny)
{
@@ -246,13 +297,16 @@ ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_access_loc_conf_t *alcf = conf;
- ngx_int_t rc;
- ngx_uint_t all;
- ngx_str_t *value;
- ngx_cidr_t cidr;
- ngx_http_access_rule_t *rule;
+ ngx_int_t rc;
+ ngx_uint_t all;
+ ngx_str_t *value;
+ ngx_cidr_t cidr;
+ ngx_http_access_rule_t *rule;
#if (NGX_HAVE_INET6)
- ngx_http_access_rule6_t *rule6;
+ ngx_http_access_rule6_t *rule6;
+#endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+ ngx_http_access_rule_un_t *rule_un;
#endif
ngx_memzero(&cidr, sizeof(ngx_cidr_t));
@@ -263,7 +317,19 @@ ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
if (!all) {
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+ if (value[1].len == 5 && ngx_strcmp(value[1].data, "unix:") == 0) {
+ cidr.family = AF_UNIX;
+ rc = NGX_OK;
+
+ } else {
+ rc = ngx_ptocidr(&value[1], &cidr);
+ }
+
+#else
rc = ngx_ptocidr(&value[1], &cidr);
+#endif
if (rc == NGX_ERROR) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -277,11 +343,28 @@ ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}
}
- switch (cidr.family) {
+ if (cidr.family == AF_INET || all) {
+
+ if (alcf->rules == NULL) {
+ alcf->rules = ngx_array_create(cf->pool, 4,
+ sizeof(ngx_http_access_rule_t));
+ if (alcf->rules == NULL) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ rule = ngx_array_push(alcf->rules);
+ if (rule == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ rule->mask = cidr.u.in.mask;
+ rule->addr = cidr.u.in.addr;
+ rule->deny = (value[0].data[0] == 'd') ? 1 : 0;
+ }
#if (NGX_HAVE_INET6)
- case AF_INET6:
- case 0: /* all */
+ if (cidr.family == AF_INET6 || all) {
if (alcf->rules6 == NULL) {
alcf->rules6 = ngx_array_create(cf->pool, 4,
@@ -299,33 +382,28 @@ ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
rule6->mask = cidr.u.in6.mask;
rule6->addr = cidr.u.in6.addr;
rule6->deny = (value[0].data[0] == 'd') ? 1 : 0;
-
- if (!all) {
- break;
- }
-
- /* "all" passes through */
+ }
#endif
- default: /* AF_INET */
+#if (NGX_HAVE_UNIX_DOMAIN)
+ if (cidr.family == AF_UNIX || all) {
- if (alcf->rules == NULL) {
- alcf->rules = ngx_array_create(cf->pool, 4,
- sizeof(ngx_http_access_rule_t));
- if (alcf->rules == NULL) {
+ if (alcf->rules_un == NULL) {
+ alcf->rules_un = ngx_array_create(cf->pool, 1,
+ sizeof(ngx_http_access_rule_un_t));
+ if (alcf->rules_un == NULL) {
return NGX_CONF_ERROR;
}
}
- rule = ngx_array_push(alcf->rules);
- if (rule == NULL) {
+ rule_un = ngx_array_push(alcf->rules_un);
+ if (rule_un == NULL) {
return NGX_CONF_ERROR;
}
- rule->mask = cidr.u.in.mask;
- rule->addr = cidr.u.in.addr;
- rule->deny = (value[0].data[0] == 'd') ? 1 : 0;
+ rule_un->deny = (value[0].data[0] == 'd') ? 1 : 0;
}
+#endif
return NGX_CONF_OK;
}
@@ -351,20 +429,22 @@ ngx_http_access_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_http_access_loc_conf_t *prev = parent;
ngx_http_access_loc_conf_t *conf = child;
+ if (conf->rules == NULL
#if (NGX_HAVE_INET6)
-
- if (conf->rules == NULL && conf->rules6 == NULL) {
+ && conf->rules6 == NULL
+#endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+ && conf->rules_un == NULL
+#endif
+ ) {
conf->rules = prev->rules;
+#if (NGX_HAVE_INET6)
conf->rules6 = prev->rules6;
- }
-
-#else
-
- if (conf->rules == NULL) {
- conf->rules = prev->rules;
- }
-
#endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+ conf->rules_un = prev->rules_un;
+#endif
+ }
return NGX_CONF_OK;
}
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_auth_basic_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_auth_basic_module.c
index 8f158dd4f7b..38892c1063c 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_auth_basic_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_auth_basic_module.c
@@ -137,7 +137,7 @@ ngx_http_auth_basic_handler(ngx_http_request_t *r)
if (rc == NGX_DECLINED) {
- ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
"no user/password was provided for basic authentication");
return ngx_http_auth_basic_set_realm(r, &realm);
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_auth_request_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_auth_request_module.c
new file mode 100644
index 00000000000..b4307be2e7d
--- /dev/null
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_auth_request_module.c
@@ -0,0 +1,444 @@
+
+/*
+ * Copyright (C) Maxim Dounin
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+typedef struct {
+ ngx_str_t uri;
+ ngx_array_t *vars;
+} ngx_http_auth_request_conf_t;
+
+
+typedef struct {
+ ngx_uint_t done;
+ ngx_uint_t status;
+ ngx_http_request_t *subrequest;
+} ngx_http_auth_request_ctx_t;
+
+
+typedef struct {
+ ngx_int_t index;
+ ngx_http_complex_value_t value;
+ ngx_http_set_variable_pt set_handler;
+} ngx_http_auth_request_variable_t;
+
+
+static ngx_int_t ngx_http_auth_request_handler(ngx_http_request_t *r);
+static ngx_int_t ngx_http_auth_request_done(ngx_http_request_t *r,
+ void *data, ngx_int_t rc);
+static ngx_int_t ngx_http_auth_request_set_variables(ngx_http_request_t *r,
+ ngx_http_auth_request_conf_t *arcf, ngx_http_auth_request_ctx_t *ctx);
+static ngx_int_t ngx_http_auth_request_variable(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data);
+static void *ngx_http_auth_request_create_conf(ngx_conf_t *cf);
+static char *ngx_http_auth_request_merge_conf(ngx_conf_t *cf,
+ void *parent, void *child);
+static ngx_int_t ngx_http_auth_request_init(ngx_conf_t *cf);
+static char *ngx_http_auth_request(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+static char *ngx_http_auth_request_set(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+
+
+static ngx_command_t ngx_http_auth_request_commands[] = {
+
+ { ngx_string("auth_request"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_http_auth_request,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ 0,
+ NULL },
+
+ { ngx_string("auth_request_set"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
+ ngx_http_auth_request_set,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ 0,
+ NULL },
+
+ ngx_null_command
+};
+
+
+static ngx_http_module_t ngx_http_auth_request_module_ctx = {
+ NULL, /* preconfiguration */
+ ngx_http_auth_request_init, /* postconfiguration */
+
+ NULL, /* create main configuration */
+ NULL, /* init main configuration */
+
+ NULL, /* create server configuration */
+ NULL, /* merge server configuration */
+
+ ngx_http_auth_request_create_conf, /* create location configuration */
+ ngx_http_auth_request_merge_conf /* merge location configuration */
+};
+
+
+ngx_module_t ngx_http_auth_request_module = {
+ NGX_MODULE_V1,
+ &ngx_http_auth_request_module_ctx, /* module context */
+ ngx_http_auth_request_commands, /* module directives */
+ NGX_HTTP_MODULE, /* module type */
+ NULL, /* init master */
+ NULL, /* init module */
+ NULL, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ NULL, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
+
+
+static ngx_int_t
+ngx_http_auth_request_handler(ngx_http_request_t *r)
+{
+ ngx_table_elt_t *h, *ho;
+ ngx_http_request_t *sr;
+ ngx_http_post_subrequest_t *ps;
+ ngx_http_auth_request_ctx_t *ctx;
+ ngx_http_auth_request_conf_t *arcf;
+
+ arcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_request_module);
+
+ if (arcf->uri.len == 0) {
+ return NGX_DECLINED;
+ }
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "auth request handler");
+
+ ctx = ngx_http_get_module_ctx(r, ngx_http_auth_request_module);
+
+ if (ctx != NULL) {
+ if (!ctx->done) {
+ return NGX_AGAIN;
+ }
+
+ /*
+ * as soon as we are done - explicitly set variables to make
+ * sure they will be available after internal redirects
+ */
+
+ if (ngx_http_auth_request_set_variables(r, arcf, ctx) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ /* return appropriate status */
+
+ if (ctx->status == NGX_HTTP_FORBIDDEN) {
+ return ctx->status;
+ }
+
+ if (ctx->status == NGX_HTTP_UNAUTHORIZED) {
+ sr = ctx->subrequest;
+
+ h = sr->headers_out.www_authenticate;
+
+ if (!h && sr->upstream) {
+ h = sr->upstream->headers_in.www_authenticate;
+ }
+
+ if (h) {
+ ho = ngx_list_push(&r->headers_out.headers);
+ if (ho == NULL) {
+ return NGX_ERROR;
+ }
+
+ *ho = *h;
+
+ r->headers_out.www_authenticate = ho;
+ }
+
+ return ctx->status;
+ }
+
+ if (ctx->status >= NGX_HTTP_OK
+ && ctx->status < NGX_HTTP_SPECIAL_RESPONSE)
+ {
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "auth request unexpected status: %d", ctx->status);
+
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_auth_request_ctx_t));
+ if (ctx == NULL) {
+ return NGX_ERROR;
+ }
+
+ ps = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));
+ if (ps == NULL) {
+ return NGX_ERROR;
+ }
+
+ ps->handler = ngx_http_auth_request_done;
+ ps->data = ctx;
+
+ if (ngx_http_subrequest(r, &arcf->uri, NULL, &sr, ps,
+ NGX_HTTP_SUBREQUEST_WAITED)
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+
+ /*
+ * allocate fake request body to avoid attempts to read it and to make
+ * sure real body file (if already read) won't be closed by upstream
+ */
+
+ sr->request_body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
+ if (sr->request_body == NULL) {
+ return NGX_ERROR;
+ }
+
+ sr->header_only = 1;
+
+ ctx->subrequest = sr;
+
+ ngx_http_set_ctx(r, ctx, ngx_http_auth_request_module);
+
+ return NGX_AGAIN;
+}
+
+
+static ngx_int_t
+ngx_http_auth_request_done(ngx_http_request_t *r, void *data, ngx_int_t rc)
+{
+ ngx_http_auth_request_ctx_t *ctx = data;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "auth request done s:%d", r->headers_out.status);
+
+ ctx->done = 1;
+ ctx->status = r->headers_out.status;
+
+ return rc;
+}
+
+
+static ngx_int_t
+ngx_http_auth_request_set_variables(ngx_http_request_t *r,
+ ngx_http_auth_request_conf_t *arcf, ngx_http_auth_request_ctx_t *ctx)
+{
+ ngx_str_t val;
+ ngx_http_variable_t *v;
+ ngx_http_variable_value_t *vv;
+ ngx_http_auth_request_variable_t *av, *last;
+ ngx_http_core_main_conf_t *cmcf;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "auth request set variables");
+
+ if (arcf->vars == NULL) {
+ return NGX_OK;
+ }
+
+ cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
+ v = cmcf->variables.elts;
+
+ av = arcf->vars->elts;
+ last = av + arcf->vars->nelts;
+
+ while (av < last) {
+ /*
+ * explicitly set new value to make sure it will be available after
+ * internal redirects
+ */
+
+ vv = &r->variables[av->index];
+
+ if (ngx_http_complex_value(ctx->subrequest, &av->value, &val)
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+
+ vv->valid = 1;
+ vv->not_found = 0;
+ vv->data = val.data;
+ vv->len = val.len;
+
+ if (av->set_handler) {
+ /*
+ * set_handler only available in cmcf->variables_keys, so we store
+ * it explicitly
+ */
+
+ av->set_handler(r, vv, v[av->index].data);
+ }
+
+ av++;
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_auth_request_variable(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data)
+{
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "auth request variable");
+
+ v->not_found = 1;
+
+ return NGX_OK;
+}
+
+
+static void *
+ngx_http_auth_request_create_conf(ngx_conf_t *cf)
+{
+ ngx_http_auth_request_conf_t *conf;
+
+ conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_auth_request_conf_t));
+ if (conf == NULL) {
+ return NULL;
+ }
+
+ /*
+ * set by ngx_pcalloc():
+ *
+ * conf->uri = { 0, NULL };
+ */
+
+ conf->vars = NGX_CONF_UNSET_PTR;
+
+ return conf;
+}
+
+
+static char *
+ngx_http_auth_request_merge_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+ ngx_http_auth_request_conf_t *prev = parent;
+ ngx_http_auth_request_conf_t *conf = child;
+
+ ngx_conf_merge_str_value(conf->uri, prev->uri, "");
+ ngx_conf_merge_ptr_value(conf->vars, prev->vars, NULL);
+
+ return NGX_CONF_OK;
+}
+
+
+static ngx_int_t
+ngx_http_auth_request_init(ngx_conf_t *cf)
+{
+ ngx_http_handler_pt *h;
+ ngx_http_core_main_conf_t *cmcf;
+
+ cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
+
+ h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
+ if (h == NULL) {
+ return NGX_ERROR;
+ }
+
+ *h = ngx_http_auth_request_handler;
+
+ return NGX_OK;
+}
+
+
+static char *
+ngx_http_auth_request(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_auth_request_conf_t *arcf = conf;
+
+ ngx_str_t *value;
+
+ if (arcf->uri.data != NULL) {
+ return "is duplicate";
+ }
+
+ value = cf->args->elts;
+
+ if (ngx_strcmp(value[1].data, "off") == 0) {
+ arcf->uri.len = 0;
+ arcf->uri.data = (u_char *) "";
+
+ return NGX_CONF_OK;
+ }
+
+ arcf->uri = value[1];
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_http_auth_request_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_auth_request_conf_t *arcf = conf;
+
+ ngx_str_t *value;
+ ngx_http_variable_t *v;
+ ngx_http_auth_request_variable_t *av;
+ ngx_http_compile_complex_value_t ccv;
+
+ value = cf->args->elts;
+
+ if (value[1].data[0] != '$') {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid variable name \"%V\"", &value[1]);
+ return NGX_CONF_ERROR;
+ }
+
+ value[1].len--;
+ value[1].data++;
+
+ if (arcf->vars == NGX_CONF_UNSET_PTR) {
+ arcf->vars = ngx_array_create(cf->pool, 1,
+ sizeof(ngx_http_auth_request_variable_t));
+ if (arcf->vars == NULL) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ av = ngx_array_push(arcf->vars);
+ if (av == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ v = ngx_http_add_variable(cf, &value[1], NGX_HTTP_VAR_CHANGEABLE);
+ if (v == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ av->index = ngx_http_get_variable_index(cf, &value[1]);
+ if (av->index == NGX_ERROR) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (v->get_handler == NULL) {
+ v->get_handler = ngx_http_auth_request_variable;
+ v->data = (uintptr_t) av;
+ }
+
+ av->set_handler = v->set_handler;
+
+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+ ccv.cf = cf;
+ ccv.value = &value[2];
+ ccv.complex_value = &av->value;
+
+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_autoindex_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_autoindex_module.c
index 1eecfbe689c..f694df075db 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_autoindex_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_autoindex_module.c
@@ -233,6 +233,7 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_type_len = sizeof("text/html") - 1;
ngx_str_set(&r->headers_out.content_type, "text/html");
+ r->headers_out.content_type_lowcase = NULL;
rc = ngx_http_send_header(r);
@@ -357,7 +358,7 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
if (ngx_close_dir(&dir) == NGX_ERROR) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
- ngx_close_dir_n " \"%s\" failed", &path);
+ ngx_close_dir_n " \"%V\" failed", &path);
}
escape_html = ngx_escape_html(NULL, r->uri.data, r->uri.len);
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_charset_filter_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_charset_filter_module.c
index 27a00d09aee..c9b7e9e8968 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_charset_filter_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_charset_filter_module.c
@@ -128,7 +128,7 @@ ngx_str_t ngx_http_charset_default_types[] = {
ngx_string("text/xml"),
ngx_string("text/plain"),
ngx_string("text/vnd.wap.wml"),
- ngx_string("application/x-javascript"),
+ ngx_string("application/javascript"),
ngx_string("application/rss+xml"),
ngx_null_string
};
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_dav_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_dav_module.c
index a97c60e44de..e7f9e9ae3c8 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_dav_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_dav_module.c
@@ -10,8 +10,6 @@
#include <ngx_http.h>
-#define NGX_HTTP_DAV_COPY_BLOCK 65536
-
#define NGX_HTTP_DAV_OFF 2
@@ -606,7 +604,7 @@ destination_done:
duri.len = last - p;
duri.data = p;
- flags = 0;
+ flags = NGX_HTTP_LOG_UNSAFE;
if (ngx_http_parse_unsafe_uri(r, &duri, &args, &flags) != NGX_OK) {
goto invalid_destination;
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_fastcgi_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_fastcgi_module.c
index e2427b4a885..80cd1a220a6 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_fastcgi_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_fastcgi_module.c
@@ -138,6 +138,8 @@ static ngx_int_t ngx_http_fastcgi_process_header(ngx_http_request_t *r);
static ngx_int_t ngx_http_fastcgi_input_filter_init(void *data);
static ngx_int_t ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p,
ngx_buf_t *buf);
+static ngx_int_t ngx_http_fastcgi_non_buffered_filter(void *data,
+ ssize_t bytes);
static ngx_int_t ngx_http_fastcgi_process_record(ngx_http_request_t *r,
ngx_http_fastcgi_ctx_t *f);
static void ngx_http_fastcgi_abort_request(ngx_http_request_t *r);
@@ -185,6 +187,7 @@ static ngx_conf_bitmask_t ngx_http_fastcgi_next_upstream_masks[] = {
{ ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
{ ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
{ ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
+ { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 },
{ ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
{ ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING },
{ ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
@@ -232,6 +235,13 @@ static ngx_command_t ngx_http_fastcgi_commands[] = {
offsetof(ngx_http_fastcgi_loc_conf_t, upstream.store_access),
NULL },
+ { ngx_string("fastcgi_buffering"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_fastcgi_loc_conf_t, upstream.buffering),
+ NULL },
+
{ ngx_string("fastcgi_ignore_client_abort"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
@@ -395,6 +405,13 @@ static ngx_command_t ngx_http_fastcgi_commands[] = {
offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_lock_timeout),
NULL },
+ { ngx_string("fastcgi_cache_revalidate"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_revalidate),
+ NULL },
+
#endif
{ ngx_string("fastcgi_temp_path"),
@@ -553,7 +570,8 @@ static ngx_str_t ngx_http_fastcgi_hide_headers[] = {
#if (NGX_HTTP_CACHE)
static ngx_keyval_t ngx_http_fastcgi_cache_headers[] = {
- { ngx_string("HTTP_IF_MODIFIED_SINCE"), ngx_string("") },
+ { ngx_string("HTTP_IF_MODIFIED_SINCE"),
+ ngx_string("$upstream_cache_last_modified") },
{ ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") },
{ ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("") },
{ ngx_string("HTTP_IF_MATCH"), ngx_string("") },
@@ -578,13 +596,6 @@ ngx_http_fastcgi_handler(ngx_http_request_t *r)
ngx_http_fastcgi_ctx_t *f;
ngx_http_fastcgi_loc_conf_t *flcf;
- if (r->subrequest_in_memory) {
- ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
- "ngx_http_fastcgi_module does not support "
- "subrequest in memory");
- return NGX_HTTP_INTERNAL_SERVER_ERROR;
- }
-
if (ngx_http_upstream_create(r) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
@@ -621,7 +632,7 @@ ngx_http_fastcgi_handler(ngx_http_request_t *r)
u->finalize_request = ngx_http_fastcgi_finalize_request;
r->state = 0;
- u->buffering = 1;
+ u->buffering = flcf->upstream.buffering;
u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
if (u->pipe == NULL) {
@@ -632,6 +643,8 @@ ngx_http_fastcgi_handler(ngx_http_request_t *r)
u->pipe->input_ctx = r;
u->input_filter_init = ngx_http_fastcgi_input_filter_init;
+ u->input_filter = ngx_http_fastcgi_non_buffered_filter;
+ u->input_filter_ctx = r;
rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
@@ -1582,7 +1595,7 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r)
ngx_str_set(&u->headers_in.status_line, "200 OK");
}
- if (u->state) {
+ if (u->state && u->state->status == 0) {
u->state->status = u->headers_in.status_n;
}
@@ -1825,19 +1838,13 @@ ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
break;
}
- if (p->free) {
- cl = p->free;
- b = cl->buf;
- p->free = cl->next;
- ngx_free_chain(p->pool, cl);
-
- } else {
- b = ngx_alloc_buf(p->pool);
- if (b == NULL) {
- return NGX_ERROR;
- }
+ cl = ngx_chain_get_free_buf(p->pool, &p->free);
+ if (cl == NULL) {
+ return NGX_ERROR;
}
+ b = cl->buf;
+
ngx_memzero(b, sizeof(ngx_buf_t));
b->pos = f->pos;
@@ -1850,14 +1857,6 @@ ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
*prev = b;
prev = &b->shadow;
- cl = ngx_alloc_chain_link(p->pool);
- if (cl == NULL) {
- return NGX_ERROR;
- }
-
- cl->buf = b;
- cl->next = NULL;
-
if (p->in) {
*p->last_in = cl;
} else {
@@ -1925,6 +1924,222 @@ ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
static ngx_int_t
+ngx_http_fastcgi_non_buffered_filter(void *data, ssize_t bytes)
+{
+ u_char *m, *msg;
+ ngx_int_t rc;
+ ngx_buf_t *b, *buf;
+ ngx_chain_t *cl, **ll;
+ ngx_http_request_t *r;
+ ngx_http_upstream_t *u;
+ ngx_http_fastcgi_ctx_t *f;
+
+ r = data;
+ f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
+
+ u = r->upstream;
+ buf = &u->buffer;
+
+ buf->pos = buf->last;
+ buf->last += bytes;
+
+ for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
+ ll = &cl->next;
+ }
+
+ f->pos = buf->pos;
+ f->last = buf->last;
+
+ for ( ;; ) {
+ if (f->state < ngx_http_fastcgi_st_data) {
+
+ rc = ngx_http_fastcgi_process_record(r, f);
+
+ if (rc == NGX_AGAIN) {
+ break;
+ }
+
+ if (rc == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+
+ if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) {
+ f->state = ngx_http_fastcgi_st_padding;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http fastcgi closed stdout");
+
+ continue;
+ }
+ }
+
+ if (f->state == ngx_http_fastcgi_st_padding) {
+
+ if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
+
+ if (f->pos + f->padding < f->last) {
+ u->length = 0;
+ break;
+ }
+
+ if (f->pos + f->padding == f->last) {
+ u->length = 0;
+ u->keepalive = 1;
+ break;
+ }
+
+ f->padding -= f->last - f->pos;
+
+ break;
+ }
+
+ if (f->pos + f->padding < f->last) {
+ f->state = ngx_http_fastcgi_st_version;
+ f->pos += f->padding;
+
+ continue;
+ }
+
+ if (f->pos + f->padding == f->last) {
+ f->state = ngx_http_fastcgi_st_version;
+
+ break;
+ }
+
+ f->padding -= f->last - f->pos;
+
+ break;
+ }
+
+
+ /* f->state == ngx_http_fastcgi_st_data */
+
+ if (f->type == NGX_HTTP_FASTCGI_STDERR) {
+
+ if (f->length) {
+
+ if (f->pos == f->last) {
+ break;
+ }
+
+ msg = f->pos;
+
+ if (f->pos + f->length <= f->last) {
+ f->pos += f->length;
+ f->length = 0;
+ f->state = ngx_http_fastcgi_st_padding;
+
+ } else {
+ f->length -= f->last - f->pos;
+ f->pos = f->last;
+ }
+
+ for (m = f->pos - 1; msg < m; m--) {
+ if (*m != LF && *m != CR && *m != '.' && *m != ' ') {
+ break;
+ }
+ }
+
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "FastCGI sent in stderr: \"%*s\"",
+ m + 1 - msg, msg);
+
+ } else {
+ f->state = ngx_http_fastcgi_st_padding;
+ }
+
+ continue;
+ }
+
+ if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
+
+ if (f->pos + f->length <= f->last) {
+ f->state = ngx_http_fastcgi_st_padding;
+ f->pos += f->length;
+
+ continue;
+ }
+
+ f->length -= f->last - f->pos;
+
+ break;
+ }
+
+
+ /* f->type == NGX_HTTP_FASTCGI_STDOUT */
+
+ if (f->pos == f->last) {
+ break;
+ }
+
+ cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
+ if (cl == NULL) {
+ return NGX_ERROR;
+ }
+
+ *ll = cl;
+ ll = &cl->next;
+
+ b = cl->buf;
+
+ b->flush = 1;
+ b->memory = 1;
+
+ b->pos = f->pos;
+ b->tag = u->output.tag;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http fastcgi output buf %p", b->pos);
+
+ if (f->pos + f->length <= f->last) {
+ f->state = ngx_http_fastcgi_st_padding;
+ f->pos += f->length;
+ b->last = f->pos;
+
+ continue;
+ }
+
+ f->length -= f->last - f->pos;
+ b->last = f->last;
+
+ break;
+ }
+
+ /* provide continuous buffer for subrequests in memory */
+
+ if (r->subrequest_in_memory) {
+
+ cl = u->out_bufs;
+
+ if (cl) {
+ buf->pos = cl->buf->pos;
+ }
+
+ buf->last = buf->pos;
+
+ for (cl = u->out_bufs; cl; cl = cl->next) {
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http fastcgi in memory %p-%p %uz",
+ cl->buf->pos, cl->buf->last, ngx_buf_size(cl->buf));
+
+ if (buf->last == cl->buf->pos) {
+ buf->last = cl->buf->last;
+ continue;
+ }
+
+ buf->last = ngx_movemem(buf->last, cl->buf->pos,
+ cl->buf->last - cl->buf->pos);
+
+ cl->buf->pos = buf->last - (cl->buf->last - cl->buf->pos);
+ cl->buf->last = buf->last;
+ }
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
ngx_http_fastcgi_process_record(ngx_http_request_t *r,
ngx_http_fastcgi_ctx_t *f)
{
@@ -2126,6 +2341,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
conf->upstream.cache_lock = NGX_CONF_UNSET;
conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
+ conf->upstream.cache_revalidate = NGX_CONF_UNSET;
#endif
conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
@@ -2136,6 +2352,8 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
/* "fastcgi_cyclic_temp_file" is disabled */
conf->upstream.cyclic_temp_file = 0;
+ conf->upstream.change_buffering = 1;
+
conf->catch_stderr = NGX_CONF_UNSET_PTR;
conf->keep_conn = NGX_CONF_UNSET;
@@ -2357,12 +2575,6 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_ptr_value(conf->upstream.no_cache,
prev->upstream.no_cache, NULL);
- if (conf->upstream.no_cache && conf->upstream.cache_bypass == NULL) {
- ngx_log_error(NGX_LOG_WARN, cf->log, 0,
- "\"fastcgi_no_cache\" functionality has been changed in 0.8.46, "
- "now it should be used together with \"fastcgi_cache_bypass\"");
- }
-
ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
prev->upstream.cache_valid, NULL);
@@ -2376,6 +2588,9 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
prev->upstream.cache_lock_timeout, 5000);
+ ngx_conf_merge_value(conf->upstream.cache_revalidate,
+ prev->upstream.cache_revalidate, 0);
+
#endif
ngx_conf_merge_value(conf->upstream.pass_request_headers,
@@ -2551,7 +2766,7 @@ ngx_http_fastcgi_merge_params(ngx_conf_t *cf,
s->key = h->key;
s->value = h->value;
- s->skip_empty = 0;
+ s->skip_empty = 1;
next:
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_gunzip_filter_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_gunzip_filter_module.c
index d4e41e4a007..adadc9da6dd 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_gunzip_filter_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_gunzip_filter_module.c
@@ -199,7 +199,7 @@ ngx_http_gunzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
}
}
- if (ctx->nomem) {
+ if (ctx->nomem || in == NULL) {
/* flush busy buffers */
@@ -422,7 +422,7 @@ ngx_http_gunzip_filter_inflate(ngx_http_request_t *r,
rc = inflate(&ctx->zstream, ctx->flush);
if (rc != Z_OK && rc != Z_STREAM_END && rc != Z_BUF_ERROR) {
- ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"inflate() failed: %d, %d", ctx->flush, rc);
return NGX_ERROR;
}
@@ -500,9 +500,13 @@ ngx_http_gunzip_filter_inflate(ngx_http_request_t *r,
return NGX_OK;
}
- if (rc == Z_STREAM_END && ctx->flush == Z_FINISH
- && ctx->zstream.avail_in == 0)
- {
+ if (ctx->flush == Z_FINISH && ctx->zstream.avail_in == 0) {
+
+ if (rc != Z_STREAM_END) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "inflate() returned %d on response end", rc);
+ return NGX_ERROR;
+ }
if (ngx_http_gunzip_filter_inflate_end(r, ctx) != NGX_OK) {
return NGX_ERROR;
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_gzip_filter_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_gzip_filter_module.c
index 35dd07ec473..ea1f1d0b9a2 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_gzip_filter_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_gzip_filter_module.c
@@ -368,9 +368,11 @@ ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) {
goto failed;
}
+
+ r->connection->buffered |= NGX_HTTP_GZIP_BUFFERED;
}
- if (ctx->nomem) {
+ if (ctx->nomem || in == NULL) {
/* flush busy buffers */
@@ -620,8 +622,6 @@ ngx_http_gzip_filter_deflate_start(ngx_http_request_t *r,
return NGX_ERROR;
}
- r->connection->buffered |= NGX_HTTP_GZIP_BUFFERED;
-
ctx->last_out = &ctx->out;
ctx->crc32 = crc32(0L, Z_NULL, 0);
ctx->flush = Z_NO_FLUSH;
@@ -854,6 +854,8 @@ ngx_http_gzip_filter_deflate(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
*ctx->last_out = cl;
ctx->last_out = &cl->next;
+ r->connection->buffered &= ~NGX_HTTP_GZIP_BUFFERED;
+
return NGX_OK;
}
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_gzip_static_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_gzip_static_module.c
index 6e777619b43..1746e550423 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_gzip_static_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_gzip_static_module.c
@@ -38,7 +38,7 @@ static ngx_conf_enum_t ngx_http_gzip_static[] = {
static ngx_command_t ngx_http_gzip_static_commands[] = {
{ ngx_string("gzip_static"),
- NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_enum_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_gzip_static_conf_t, enable),
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_headers_filter_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_headers_filter_module.c
index 0dfe8101ed6..e33e7ce5271 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_headers_filter_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_headers_filter_module.c
@@ -339,6 +339,10 @@ ngx_http_add_cache_control(ngx_http_request_t *r, ngx_http_header_val_t *hv,
{
ngx_table_elt_t *cc, **ccp;
+ if (value->len == 0) {
+ return NGX_OK;
+ }
+
ccp = r->headers_out.cache_control.elts;
if (ccp == NULL) {
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_image_filter_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_image_filter_module.c
index c6c3b747a32..c983b973b46 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_image_filter_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_image_filter_module.c
@@ -478,7 +478,12 @@ ngx_http_image_read(ngx_http_request_t *r, ngx_chain_t *in)
"image buf: %uz", size);
rest = ctx->image + ctx->length - p;
- size = (rest < size) ? rest : size;
+
+ if (size > rest) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "image filter: too big response");
+ return NGX_ERROR;
+ }
p = ngx_cpymem(p, b->pos, size);
b->pos += size;
@@ -567,7 +572,8 @@ ngx_http_image_json(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx)
ngx_http_clean_header(r);
r->headers_out.status = NGX_HTTP_OK;
- ngx_str_set(&r->headers_out.content_type, "text/plain");
+ r->headers_out.content_type_len = sizeof("application/json") - 1;
+ ngx_str_set(&r->headers_out.content_type, "application/json");
r->headers_out.content_type_lowcase = NULL;
if (ctx == NULL) {
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_limit_req_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_limit_req_module.c
index 90434c956a6..74f7fdaa75f 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_limit_req_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_limit_req_module.c
@@ -451,6 +451,8 @@ ngx_http_limit_req_lookup(ngx_http_limit_req_limit_t *limit, ngx_uint_t hash,
node = ngx_slab_alloc_locked(ctx->shpool, size);
if (node == NULL) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
+ "could not allocate node%s", ctx->shpool->log_ctx);
return NGX_ERROR;
}
}
@@ -674,6 +676,8 @@ ngx_http_limit_req_init_zone(ngx_shm_zone_t *shm_zone, void *data)
ngx_sprintf(ctx->shpool->log_ctx, " in limit_req zone \"%V\"%Z",
&shm_zone->shm.name);
+ ctx->shpool->log_nomem = 0;
+
return NGX_OK;
}
@@ -912,7 +916,7 @@ ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
continue;
}
- if (ngx_strncmp(value[i].data, "nodelay", 7) == 0) {
+ if (ngx_strcmp(value[i].data, "nodelay") == 0) {
nodelay = 1;
continue;
}
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_log_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_log_module.c
index fe34fa5a92d..cd9afa7ac9e 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_log_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_log_module.c
@@ -13,11 +13,6 @@
#include <zlib.h>
#endif
-#if (NGX_ENABLE_SYSLOG)
-#include <syslog.h>
-
-#define HTTP_SYSLOG_PRIORITY LOG_NOTICE
-#endif
typedef struct ngx_http_log_op_s ngx_http_log_op_t;
@@ -71,12 +66,8 @@ typedef struct {
ngx_http_log_script_t *script;
time_t disk_full_time;
time_t error_log_time;
+ ngx_syslog_peer_t *syslog_peer;
ngx_http_log_fmt_t *format;
-
-#if (NGX_ENABLE_SYSLOG)
- ngx_int_t priority;
- unsigned syslog_on:1; /* unsigned :1 syslog_on */
-#endif
} ngx_http_log_t;
@@ -249,7 +240,8 @@ static ngx_int_t
ngx_http_log_handler(ngx_http_request_t *r)
{
u_char *line, *p;
- size_t len;
+ size_t len, size;
+ ssize_t n;
ngx_uint_t i, l;
ngx_http_log_t *log;
ngx_http_log_op_t *op;
@@ -292,6 +284,16 @@ ngx_http_log_handler(ngx_http_request_t *r)
}
}
+ if (log[l].syslog_peer) {
+
+ /* length of syslog's PRI and HEADER message parts */
+ len += sizeof("<255>Jan 01 00:00:00 ") - 1
+ + ngx_cycle->hostname.len + 1
+ + log[l].syslog_peer->tag.len + 2;
+
+ goto alloc_line;
+ }
+
len += NGX_LINEFEED_SIZE;
buffer = log[l].file ? log[l].file->data : NULL;
@@ -330,6 +332,8 @@ ngx_http_log_handler(ngx_http_request_t *r)
}
}
+ alloc_line:
+
line = ngx_pnalloc(r->pool, len);
if (line == NULL) {
return NGX_ERROR;
@@ -337,10 +341,33 @@ ngx_http_log_handler(ngx_http_request_t *r)
p = line;
+ if (log[l].syslog_peer) {
+ p = ngx_syslog_add_header(log[l].syslog_peer, line);
+ }
+
for (i = 0; i < log[l].format->ops->nelts; i++) {
p = op[i].run(r, p, &op[i]);
}
+ if (log[l].syslog_peer) {
+
+ size = p - line;
+
+ n = ngx_syslog_send(log[l].syslog_peer, line, size);
+
+ if (n < 0) {
+ ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
+ "send() to syslog failed");
+
+ } else if ((size_t) n != size) {
+ ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
+ "send() to syslog has written only %z of %uz",
+ n, size);
+ }
+
+ continue;
+ }
+
ngx_linefeed(p);
ngx_http_log_write(r, &log[l], line, p - line);
@@ -358,24 +385,13 @@ ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf,
time_t now;
ssize_t n;
ngx_err_t err;
-
#if (NGX_ZLIB)
ngx_http_log_buf_t *buffer;
#endif
-#if (NGX_ENABLE_SYSLOG)
- n = 0;
- if (log->syslog_on) {
- syslog(log->priority, "%.*s", (int)len, buf);
- }
-#endif
-
if (log->script == NULL) {
name = log->file->name.data;
-#if (NGX_ENABLE_SYSLOG)
- if (name != NULL) {
-#endif
#if (NGX_ZLIB)
buffer = log->file->data;
@@ -388,11 +404,7 @@ ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf,
#else
n = ngx_write_fd(log->file->fd, buf, len);
#endif
-#if (NGX_ENABLE_SYSLOG)
- } else {
- n = len;
- }
-#endif
+
} else {
name = NULL;
n = ngx_http_log_script_write(r, log->script, &name, buf, len);
@@ -1093,10 +1105,7 @@ ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
log->script = NULL;
log->disk_full_time = 0;
log->error_log_time = 0;
-#if (NGX_ENABLE_SYSLOG)
- log->priority = HTTP_SYSLOG_PRIORITY;
- log->syslog_on = 0;
-#endif
+ log->syslog_peer = NULL;
lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
fmt = lmcf->formats.elts;
@@ -1120,18 +1129,12 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ngx_msec_t flush;
ngx_str_t *value, name, s;
ngx_http_log_t *log;
+ ngx_syslog_peer_t *peer;
ngx_http_log_buf_t *buffer;
ngx_http_log_fmt_t *fmt;
ngx_http_log_main_conf_t *lmcf;
ngx_http_script_compile_t sc;
-#if (NGX_ENABLE_SYSLOG)
- u_char *off;
- ngx_str_t priority;
- ngx_uint_t syslog_on = 0;
- name = priority = (ngx_str_t)ngx_null_string;
-#endif
-
value = cf->args->elts;
if (ngx_strcmp(value[1].data, "off") == 0) {
@@ -1144,38 +1147,6 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
"invalid parameter \"%V\"", &value[2]);
return NGX_CONF_ERROR;
}
-#if (NGX_ENABLE_SYSLOG)
- else if (ngx_strncmp(value[1].data, "syslog", sizeof("syslog") - 1) == 0) {
- if (!cf->cycle->new_log.syslog_set) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "You must set the syslog directive and enable it first.");
- return NGX_CONF_ERROR;
- }
-
- syslog_on = 1;
- if (value[1].data[sizeof("syslog") - 1] == ':') {
- priority.len = value[1].len - sizeof("syslog");
- priority.data = value[1].data + sizeof("syslog");
-
- off = (u_char*) ngx_strchr(priority.data, '|');
- if (off != NULL) {
- priority.len = off - priority.data;
-
- off++;
- name.len = value[1].data + value[1].len - off;
- name.data = off;
- }
- }
- else {
- if (value[1].len > sizeof("syslog")) {
- name.len = value[1].len - sizeof("syslog");
- name.data = value[1].data + sizeof("syslog");
- }
- }
- } else {
- name = value[1];
- }
-#endif
if (llcf->logs == NULL) {
llcf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
@@ -1193,52 +1164,23 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ngx_memzero(log, sizeof(ngx_http_log_t));
-#if (NGX_ENABLE_SYSLOG)
- log->syslog_on = syslog_on;
-
- if (priority.len == 0) {
- log->priority = HTTP_SYSLOG_PRIORITY;
- }
- else {
- log->priority = ngx_log_get_priority(cf, &priority);
- }
- if (name.len != 0) {
- n = ngx_http_script_variables_count(&name);
+ if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) {
- if (n == 0) {
- log->file = ngx_conf_open_file(cf->cycle, &name);
- if (log->file == NULL) {
- return NGX_CONF_ERROR;
- }
- } else {
- if (ngx_conf_full_name(cf->cycle, &name, 0) != NGX_OK) {
- return NGX_CONF_ERROR;
- }
- log->script = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_script_t));
- if (log->script == NULL) {
- return NGX_CONF_ERROR;
- }
- ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
- sc.cf = cf;
- sc.source = &name;
- sc.lengths = &log->script->lengths;
- sc.values = &log->script->values;
- sc.variables = n;
- sc.complete_lengths = 1;
- sc.complete_values = 1;
- if (ngx_http_script_compile(&sc) != NGX_OK) {
- return NGX_CONF_ERROR;
- }
+ peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t));
+ if (peer == NULL) {
+ return NGX_CONF_ERROR;
}
- }
- else {
- log->file = ngx_conf_open_file(cf->cycle, &name);
- if (log->file == NULL) {
+
+ if (ngx_syslog_process_conf(cf, peer) != NGX_CONF_OK) {
return NGX_CONF_ERROR;
}
+
+ log->syslog_peer = peer;
+
+ goto process_formats;
}
-#else
+
n = ngx_http_script_variables_count(&value[1]);
if (n == 0) {
@@ -1271,7 +1213,8 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return NGX_CONF_ERROR;
}
}
-#endif
+
+process_formats:
if (cf->args->nelts >= 3) {
name = value[2];
@@ -1301,6 +1244,17 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return NGX_CONF_ERROR;
}
+ if (log->syslog_peer != NULL) {
+ if (cf->args->nelts > 3) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "parameter \"%V\" is not supported by syslog",
+ &value[3]);
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+ }
+
size = 0;
flush = 0;
gzip = 0;
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_map_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_map_module.c
index 13c8b97ff66..3245e04132c 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_map_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_map_module.c
@@ -131,7 +131,7 @@ ngx_http_map_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
}
if (!value->valid) {
- value = ngx_http_get_flushed_variable(r, (ngx_uint_t) value->data);
+ value = ngx_http_get_flushed_variable(r, (uintptr_t) value->data);
if (value == NULL || value->not_found) {
value = &ngx_http_variable_null_value;
@@ -414,7 +414,7 @@ ngx_http_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
var = ctx->var_values.elts;
for (i = 0; i < ctx->var_values.nelts; i++) {
- if (index == (ngx_int_t) var[i].data) {
+ if (index == (intptr_t) var[i].data) {
var = &var[i];
goto found;
}
@@ -429,7 +429,7 @@ ngx_http_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
var->no_cacheable = 0;
var->not_found = 0;
var->len = 0;
- var->data = (u_char *) index;
+ var->data = (u_char *) (intptr_t) index;
goto found;
}
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_memcached_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_memcached_module.c
index 278b1ed8ad6..aaa047e8fb7 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_memcached_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_memcached_module.c
@@ -197,7 +197,6 @@ ngx_http_memcached_handler(ngx_http_request_t *r)
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
- ctx->rest = NGX_HTTP_MEMCACHED_END;
ctx->request = r;
ngx_http_set_ctx(r, ctx, ngx_http_memcached_module);
@@ -309,10 +308,15 @@ ngx_http_memcached_process_header(ngx_http_request_t *r)
found:
- *p = '\0';
-
- line.len = p - u->buffer.pos - 1;
line.data = u->buffer.pos;
+ line.len = p - u->buffer.pos;
+
+ if (line.len == 0 || *(p - 1) != CR) {
+ goto no_valid;
+ }
+
+ *p = '\0';
+ line.len--;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"memcached: \"%V\"", &line);
@@ -387,10 +391,9 @@ found:
length:
start = p;
+ p = line.data + line.len;
- while (*p && *p++ != CR) { /* void */ }
-
- u->headers_in.content_length_n = ngx_atoof(start, p - start - 1);
+ u->headers_in.content_length_n = ngx_atoof(start, p - start);
if (u->headers_in.content_length_n == -1) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"memcached sent invalid length in response \"%V\" "
@@ -401,7 +404,7 @@ found:
u->headers_in.status_n = 200;
u->state->status = 200;
- u->buffer.pos = p + 1;
+ u->buffer.pos = p + sizeof(CRLF) - 1;
return NGX_OK;
}
@@ -410,8 +413,10 @@ found:
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
"key: \"%V\" was not found by memcached", &ctx->key);
+ u->headers_in.content_length_n = 0;
u->headers_in.status_n = 404;
u->state->status = 404;
+ u->buffer.pos = p + sizeof("END" CRLF) - 1;
u->keepalive = 1;
return NGX_OK;
@@ -435,7 +440,13 @@ ngx_http_memcached_filter_init(void *data)
u = ctx->request->upstream;
- u->length += NGX_HTTP_MEMCACHED_END;
+ if (u->headers_in.status_n != 404) {
+ u->length = u->headers_in.content_length_n + NGX_HTTP_MEMCACHED_END;
+ ctx->rest = NGX_HTTP_MEMCACHED_END;
+
+ } else {
+ u->length = 0;
+ }
return NGX_OK;
}
@@ -509,7 +520,7 @@ ngx_http_memcached_filter(void *data, ssize_t bytes)
return NGX_OK;
}
- last += u->length - NGX_HTTP_MEMCACHED_END;
+ last += (size_t) (u->length - NGX_HTTP_MEMCACHED_END);
if (ngx_strncmp(last, ngx_http_memcached_end, b->last - last) != 0) {
ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0,
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_mp4_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_mp4_module.c
index 20ef51af2b6..8f439ba9239 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_mp4_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_mp4_module.c
@@ -27,14 +27,15 @@
#define NGX_HTTP_MP4_CTTS_ATOM 15
#define NGX_HTTP_MP4_CTTS_DATA 16
#define NGX_HTTP_MP4_STSC_ATOM 17
-#define NGX_HTTP_MP4_STSC_CHUNK 18
+#define NGX_HTTP_MP4_STSC_START 18
#define NGX_HTTP_MP4_STSC_DATA 19
-#define NGX_HTTP_MP4_STSZ_ATOM 20
-#define NGX_HTTP_MP4_STSZ_DATA 21
-#define NGX_HTTP_MP4_STCO_ATOM 22
-#define NGX_HTTP_MP4_STCO_DATA 23
-#define NGX_HTTP_MP4_CO64_ATOM 24
-#define NGX_HTTP_MP4_CO64_DATA 25
+#define NGX_HTTP_MP4_STSC_END 20
+#define NGX_HTTP_MP4_STSZ_ATOM 21
+#define NGX_HTTP_MP4_STSZ_DATA 22
+#define NGX_HTTP_MP4_STCO_ATOM 23
+#define NGX_HTTP_MP4_STCO_DATA 24
+#define NGX_HTTP_MP4_CO64_ATOM 25
+#define NGX_HTTP_MP4_CO64_DATA 26
#define NGX_HTTP_MP4_LAST_ATOM NGX_HTTP_MP4_CO64_DATA
@@ -62,10 +63,15 @@ typedef struct {
uint32_t chunks;
ngx_uint_t start_sample;
+ ngx_uint_t end_sample;
ngx_uint_t start_chunk;
- ngx_uint_t chunk_samples;
- uint64_t chunk_samples_size;
+ ngx_uint_t end_chunk;
+ ngx_uint_t start_chunk_samples;
+ ngx_uint_t end_chunk_samples;
+ uint64_t start_chunk_samples_size;
+ uint64_t end_chunk_samples_size;
off_t start_offset;
+ off_t end_offset;
size_t tkhd_size;
size_t mdhd_size;
@@ -95,7 +101,8 @@ typedef struct {
ngx_buf_t ctts_atom_buf;
ngx_buf_t ctts_data_buf;
ngx_buf_t stsc_atom_buf;
- ngx_buf_t stsc_chunk_buf;
+ ngx_buf_t stsc_start_chunk_buf;
+ ngx_buf_t stsc_end_chunk_buf;
ngx_buf_t stsc_data_buf;
ngx_buf_t stsz_atom_buf;
ngx_buf_t stsz_data_buf;
@@ -104,7 +111,8 @@ typedef struct {
ngx_buf_t co64_atom_buf;
ngx_buf_t co64_data_buf;
- ngx_mp4_stsc_entry_t stsc_chunk_entry;
+ ngx_mp4_stsc_entry_t stsc_start_chunk_entry;
+ ngx_mp4_stsc_entry_t stsc_end_chunk_entry;
} ngx_http_mp4_trak_t;
@@ -121,6 +129,7 @@ typedef struct {
off_t end;
off_t content_length;
ngx_uint_t start;
+ ngx_uint_t length;
uint32_t timescale;
ngx_http_request_t *request;
ngx_array_t trak;
@@ -157,7 +166,11 @@ typedef struct {
#define ngx_mp4_atom_header(mp4) (mp4->buffer_pos - 8)
#define ngx_mp4_atom_data(mp4) mp4->buffer_pos
#define ngx_mp4_atom_data_size(t) (uint64_t) (sizeof(t) - 8)
-#define ngx_mp4_atom_next(mp4, n) mp4->buffer_pos += n; mp4->offset += n
+
+
+#define ngx_mp4_atom_next(mp4, n) \
+ mp4->buffer_pos += (size_t) n; \
+ mp4->offset += n
#define ngx_mp4_set_atom_name(p, n1, n2, n3, n4) \
@@ -202,6 +215,8 @@ typedef struct {
&((ngx_http_mp4_trak_t *) mp4->trak.elts)[mp4->trak.nelts - 1]
+static ngx_int_t ngx_http_mp4_handler(ngx_http_request_t *r);
+
static ngx_int_t ngx_http_mp4_process(ngx_http_mp4_file_t *mp4);
static ngx_int_t ngx_http_mp4_read_atom(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_atom_handler_t *atom, uint64_t atom_data_size);
@@ -213,7 +228,7 @@ static ngx_int_t ngx_http_mp4_read_moov_atom(ngx_http_mp4_file_t *mp4,
static ngx_int_t ngx_http_mp4_read_mdat_atom(ngx_http_mp4_file_t *mp4,
uint64_t atom_data_size);
static size_t ngx_http_mp4_update_mdat_atom(ngx_http_mp4_file_t *mp4,
- off_t start_offset);
+ off_t start_offset, off_t end_offset);
static ngx_int_t ngx_http_mp4_read_mvhd_atom(ngx_http_mp4_file_t *mp4,
uint64_t atom_data_size);
static ngx_int_t ngx_http_mp4_read_trak_atom(ngx_http_mp4_file_t *mp4,
@@ -252,18 +267,26 @@ static ngx_int_t ngx_http_mp4_read_stts_atom(ngx_http_mp4_file_t *mp4,
uint64_t atom_data_size);
static ngx_int_t ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak);
+static ngx_int_t ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4,
+ ngx_http_mp4_trak_t *trak, ngx_uint_t start);
static ngx_int_t ngx_http_mp4_read_stss_atom(ngx_http_mp4_file_t *mp4,
uint64_t atom_data_size);
static ngx_int_t ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak);
+static void ngx_http_mp4_crop_stss_data(ngx_http_mp4_file_t *mp4,
+ ngx_http_mp4_trak_t *trak, ngx_uint_t start);
static ngx_int_t ngx_http_mp4_read_ctts_atom(ngx_http_mp4_file_t *mp4,
uint64_t atom_data_size);
static void ngx_http_mp4_update_ctts_atom(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak);
+static void ngx_http_mp4_crop_ctts_data(ngx_http_mp4_file_t *mp4,
+ ngx_http_mp4_trak_t *trak, ngx_uint_t start);
static ngx_int_t ngx_http_mp4_read_stsc_atom(ngx_http_mp4_file_t *mp4,
uint64_t atom_data_size);
static ngx_int_t ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak);
+static ngx_int_t ngx_http_mp4_crop_stsc_data(ngx_http_mp4_file_t *mp4,
+ ngx_http_mp4_trak_t *trak, ngx_uint_t start);
static ngx_int_t ngx_http_mp4_read_stsz_atom(ngx_http_mp4_file_t *mp4,
uint64_t atom_data_size);
static ngx_int_t ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4,
@@ -280,10 +303,12 @@ static ngx_int_t ngx_http_mp4_update_co64_atom(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak);
static void ngx_http_mp4_adjust_co64_atom(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak, off_t adjustment);
+
static char *ngx_http_mp4(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static void *ngx_http_mp4_create_conf(ngx_conf_t *cf);
static char *ngx_http_mp4_merge_conf(ngx_conf_t *cf, void *parent, void *child);
+
static ngx_command_t ngx_http_mp4_commands[] = {
{ ngx_string("mp4"),
@@ -395,8 +420,8 @@ ngx_http_mp4_handler(ngx_http_request_t *r)
{
u_char *last;
size_t root;
- ngx_int_t rc, start;
- ngx_uint_t level;
+ ngx_int_t rc, start, end;
+ ngx_uint_t level, length;
ngx_str_t path, value;
ngx_log_t *log;
ngx_buf_t *b;
@@ -501,6 +526,7 @@ ngx_http_mp4_handler(ngx_http_request_t *r)
r->allow_ranges = 1;
start = -1;
+ length = 0;
r->headers_out.content_length_n = of.size;
mp4 = NULL;
b = NULL;
@@ -518,47 +544,72 @@ ngx_http_mp4_handler(ngx_http_request_t *r)
ngx_set_errno(0);
start = (int) (strtod((char *) value.data, NULL) * 1000);
- if (ngx_errno == 0 && start >= 0) {
- r->allow_ranges = 0;
+ if (ngx_errno != 0) {
+ start = -1;
+ }
+ }
+
+ if (ngx_http_arg(r, (u_char *) "end", 3, &value) == NGX_OK) {
+
+ ngx_set_errno(0);
+ end = (int) (strtod((char *) value.data, NULL) * 1000);
+
+ if (ngx_errno != 0) {
+ end = -1;
+ }
+
+ if (end > 0) {
+ if (start < 0) {
+ start = 0;
+ }
- mp4 = ngx_pcalloc(r->pool, sizeof(ngx_http_mp4_file_t));
- if (mp4 == NULL) {
- return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ if (end > start) {
+ length = end - start;
}
+ }
+ }
+ }
- mp4->file.fd = of.fd;
- mp4->file.name = path;
- mp4->file.log = r->connection->log;;
- mp4->end = of.size;
- mp4->start = (ngx_uint_t) start;
- mp4->request = r;
+ if (start >= 0) {
+ r->single_range = 1;
- switch (ngx_http_mp4_process(mp4)) {
+ mp4 = ngx_pcalloc(r->pool, sizeof(ngx_http_mp4_file_t));
+ if (mp4 == NULL) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
- case NGX_DECLINED:
- if (mp4->buffer) {
- ngx_pfree(r->pool, mp4->buffer);
- }
+ mp4->file.fd = of.fd;
+ mp4->file.name = path;
+ mp4->file.log = r->connection->log;
+ mp4->end = of.size;
+ mp4->start = (ngx_uint_t) start;
+ mp4->length = length;
+ mp4->request = r;
- ngx_pfree(r->pool, mp4);
- mp4 = NULL;
+ switch (ngx_http_mp4_process(mp4)) {
- break;
+ case NGX_DECLINED:
+ if (mp4->buffer) {
+ ngx_pfree(r->pool, mp4->buffer);
+ }
- case NGX_OK:
- r->headers_out.content_length_n = mp4->content_length;
- break;
+ ngx_pfree(r->pool, mp4);
+ mp4 = NULL;
- default: /* NGX_ERROR */
- if (mp4->buffer) {
- ngx_pfree(r->pool, mp4->buffer);
- }
+ break;
- ngx_pfree(r->pool, mp4);
+ case NGX_OK:
+ r->headers_out.content_length_n = mp4->content_length;
+ break;
- return NGX_HTTP_INTERNAL_SERVER_ERROR;
- }
+ default: /* NGX_ERROR */
+ if (mp4->buffer) {
+ ngx_pfree(r->pool, mp4->buffer);
}
+
+ ngx_pfree(r->pool, mp4);
+
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
}
@@ -638,15 +689,15 @@ ngx_http_mp4_handler(ngx_http_request_t *r)
static ngx_int_t
ngx_http_mp4_process(ngx_http_mp4_file_t *mp4)
{
- off_t start_offset, adjustment;
+ off_t start_offset, end_offset, adjustment;
ngx_int_t rc;
ngx_uint_t i, j;
ngx_chain_t **prev;
ngx_http_mp4_trak_t *trak;
ngx_http_mp4_conf_t *conf;
- ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
- "mp4 start:%ui", mp4->start);
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "mp4 start:%ui, length:%ui", mp4->start, mp4->length);
conf = ngx_http_get_module_loc_conf(mp4->request, ngx_http_mp4_module);
@@ -688,6 +739,7 @@ ngx_http_mp4_process(ngx_http_mp4_file_t *mp4)
}
start_offset = mp4->end;
+ end_offset = 0;
trak = mp4->trak.elts;
for (i = 0; i < mp4->trak.nelts; i++) {
@@ -735,6 +787,10 @@ ngx_http_mp4_process(ngx_http_mp4_file_t *mp4)
start_offset = trak[i].start_offset;
}
+ if (end_offset < trak[i].end_offset) {
+ end_offset = trak[i].end_offset;
+ }
+
*prev = &trak[i].out[NGX_HTTP_MP4_TRAK_ATOM];
prev = &trak[i].out[NGX_HTTP_MP4_TRAK_ATOM].next;
@@ -746,6 +802,10 @@ ngx_http_mp4_process(ngx_http_mp4_file_t *mp4)
}
}
+ if (end_offset < start_offset) {
+ end_offset = start_offset;
+ }
+
mp4->moov_size += 8;
ngx_mp4_set_32value(mp4->moov_atom_header, mp4->moov_size);
@@ -762,7 +822,7 @@ ngx_http_mp4_process(ngx_http_mp4_file_t *mp4)
}
adjustment = mp4->ftyp_size + mp4->moov_size
- + ngx_http_mp4_update_mdat_atom(mp4, start_offset)
+ + ngx_http_mp4_update_mdat_atom(mp4, start_offset, end_offset)
- start_offset;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
@@ -948,7 +1008,7 @@ ngx_http_mp4_read_ftyp_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 ftyp atom");
if (atom_data_size > 1024
- || ngx_mp4_atom_data(mp4) + atom_data_size > mp4->buffer_end)
+ || ngx_mp4_atom_data(mp4) + (size_t) atom_data_size > mp4->buffer_end)
{
ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
"\"%s\" mp4 ftyp atom is too large:%uL",
@@ -1006,7 +1066,7 @@ ngx_http_mp4_read_moov_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
no_mdat = (mp4->mdat_atom.buf == NULL);
- if (no_mdat && mp4->start == 0) {
+ if (no_mdat && mp4->start == 0 && mp4->length == 0) {
/*
* send original file if moov atom resides before
* mdat atom and client requests integral file
@@ -1105,7 +1165,8 @@ ngx_http_mp4_read_mdat_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
static size_t
-ngx_http_mp4_update_mdat_atom(ngx_http_mp4_file_t *mp4, off_t start_offset)
+ngx_http_mp4_update_mdat_atom(ngx_http_mp4_file_t *mp4, off_t start_offset,
+ off_t end_offset)
{
off_t atom_data_size;
u_char *atom_header;
@@ -1113,15 +1174,16 @@ ngx_http_mp4_update_mdat_atom(ngx_http_mp4_file_t *mp4, off_t start_offset)
uint64_t atom_size;
ngx_buf_t *atom;
- atom_data_size = mp4->mdat_data.buf->file_last - start_offset;
+ atom_data_size = end_offset - start_offset;
mp4->mdat_data.buf->file_pos = start_offset;
+ mp4->mdat_data.buf->file_last = end_offset;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
"mdat new offset @%O:%O", start_offset, atom_data_size);
atom_header = mp4->mdat_atom_header;
- if ((uint64_t) atom_data_size > 0xffffffff) {
+ if ((uint64_t) atom_data_size > (uint64_t) 0xffffffff) {
atom_size = 1;
atom_header_size = sizeof(ngx_mp4_atom_header64_t);
ngx_mp4_set_64value(atom_header + sizeof(ngx_mp4_atom_header_t),
@@ -1196,7 +1258,7 @@ ngx_http_mp4_read_mvhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
u_char *atom_header;
size_t atom_size;
uint32_t timescale;
- uint64_t duration;
+ uint64_t duration, start_time, length_time;
ngx_buf_t *atom;
ngx_mp4_mvhd_atom_t *mvhd_atom;
ngx_mp4_mvhd64_atom_t *mvhd64_atom;
@@ -1239,7 +1301,24 @@ ngx_http_mp4_read_mvhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
"mvhd timescale:%uD, duration:%uL, time:%.3fs",
timescale, duration, (double) duration / timescale);
- duration -= (uint64_t) mp4->start * timescale / 1000;
+ start_time = (uint64_t) mp4->start * timescale / 1000;
+
+ if (duration < start_time) {
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
+ "\"%s\" mp4 start time exceeds file duration",
+ mp4->file.name.data);
+ return NGX_ERROR;
+ }
+
+ duration -= start_time;
+
+ if (mp4->length) {
+ length_time = (uint64_t) mp4->length * timescale / 1000;
+
+ if (duration > length_time) {
+ duration = length_time;
+ }
+ }
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
"mvhd new duration:%uL, time:%.3fs",
@@ -1296,7 +1375,7 @@ ngx_http_mp4_read_trak_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
trak->out[NGX_HTTP_MP4_TRAK_ATOM].buf = atom;
- atom_end = mp4->buffer_pos + atom_data_size;
+ atom_end = mp4->buffer_pos + (size_t) atom_data_size;
atom_file_end = mp4->offset + atom_data_size;
rc = ngx_http_mp4_read_atom(mp4, ngx_http_mp4_trak_atoms, atom_data_size);
@@ -1386,7 +1465,7 @@ ngx_http_mp4_read_tkhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
{
u_char *atom_header;
size_t atom_size;
- uint64_t duration;
+ uint64_t duration, start_time, length_time;
ngx_buf_t *atom;
ngx_http_mp4_trak_t *trak;
ngx_mp4_tkhd_atom_t *tkhd_atom;
@@ -1426,7 +1505,23 @@ ngx_http_mp4_read_tkhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
"tkhd duration:%uL, time:%.3fs",
duration, (double) duration / mp4->timescale);
- duration -= (uint64_t) mp4->start * mp4->timescale / 1000;
+ start_time = (uint64_t) mp4->start * mp4->timescale / 1000;
+
+ if (duration <= start_time) {
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "tkhd duration is less than start time");
+ return NGX_DECLINED;
+ }
+
+ duration -= start_time;
+
+ if (mp4->length) {
+ length_time = (uint64_t) mp4->length * mp4->timescale / 1000;
+
+ if (duration > length_time) {
+ duration = length_time;
+ }
+ }
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
"tkhd new duration:%uL, time:%.3fs",
@@ -1529,7 +1624,7 @@ ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
u_char *atom_header;
size_t atom_size;
uint32_t timescale;
- uint64_t duration;
+ uint64_t duration, start_time, length_time;
ngx_buf_t *atom;
ngx_http_mp4_trak_t *trak;
ngx_mp4_mdhd_atom_t *mdhd_atom;
@@ -1571,7 +1666,23 @@ ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size)
"mdhd timescale:%uD, duration:%uL, time:%.3fs",
timescale, duration, (double) duration / timescale);
- duration -= (uint64_t) mp4->start * timescale / 1000;
+ start_time = (uint64_t) mp4->start * timescale / 1000;
+
+ if (duration <= start_time) {
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "mdhd duration is less than start time");
+ return NGX_DECLINED;
+ }
+
+ duration -= start_time;
+
+ if (mp4->length) {
+ length_time = (uint64_t) mp4->length * timescale / 1000;
+
+ if (duration > length_time) {
+ duration = length_time;
+ }
+ }
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
"mdhd new duration:%uL, time:%.3fs",
@@ -1944,13 +2055,9 @@ static ngx_int_t
ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak)
{
- size_t atom_size;
- uint32_t entries, count, duration;
- uint64_t start_time;
- ngx_buf_t *atom, *data;
- ngx_uint_t start_sample;
- ngx_mp4_stts_atom_t *stts_atom;
- ngx_mp4_stts_entry_t *entry, *end;
+ size_t atom_size;
+ ngx_buf_t *atom, *data;
+ ngx_mp4_stts_atom_t *stts_atom;
/*
* mdia.minf.stbl.stts updating requires trak->timescale
@@ -1969,12 +2076,60 @@ ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4,
return NGX_ERROR;
}
- entries = trak->time_to_sample_entries;
- start_time = (uint64_t) mp4->start * trak->timescale / 1000;
+ if (ngx_http_mp4_crop_stts_data(mp4, trak, 1) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ if (ngx_http_mp4_crop_stts_data(mp4, trak, 0) != NGX_OK) {
+ return NGX_ERROR;
+ }
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
- "time-to-sample start_time:%uL", start_time);
+ "time-to-sample entries:%uD", trak->time_to_sample_entries);
+ atom_size = sizeof(ngx_mp4_stts_atom_t) + (data->last - data->pos);
+ trak->size += atom_size;
+
+ atom = trak->out[NGX_HTTP_MP4_STTS_ATOM].buf;
+ stts_atom = (ngx_mp4_stts_atom_t *) atom->pos;
+ ngx_mp4_set_32value(stts_atom->size, atom_size);
+ ngx_mp4_set_32value(stts_atom->entries, trak->time_to_sample_entries);
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4,
+ ngx_http_mp4_trak_t *trak, ngx_uint_t start)
+{
+ uint32_t count, duration, rest;
+ uint64_t start_time;
+ ngx_buf_t *data;
+ ngx_uint_t start_sample, entries, start_sec;
+ ngx_mp4_stts_entry_t *entry, *end;
+
+ if (start) {
+ start_sec = mp4->start;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "mp4 stts crop start_time:%ui", start_sec);
+
+ } else if (mp4->length) {
+ start_sec = mp4->length;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "mp4 stts crop end_time:%ui", start_sec);
+
+ } else {
+ return NGX_OK;
+ }
+
+ data = trak->out[NGX_HTTP_MP4_STTS_DATA].buf;
+
+ start_time = (uint64_t) start_sec * trak->timescale / 1000;
+
+ entries = trak->time_to_sample_entries;
start_sample = 0;
entry = (ngx_mp4_stts_entry_t *) data->pos;
end = (ngx_mp4_stts_entry_t *) data->last;
@@ -1983,13 +2138,13 @@ ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4,
count = ngx_mp4_get_32value(entry->count);
duration = ngx_mp4_get_32value(entry->duration);
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
- "count:%uD, duration:%uD", count, duration);
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "time:%uL, count:%uD, duration:%uD",
+ start_time, count, duration);
if (start_time < (uint64_t) count * duration) {
start_sample += (ngx_uint_t) (start_time / duration);
- count -= (uint32_t) (start_time / duration);
- ngx_mp4_set_32value(entry->count, count);
+ rest = (uint32_t) (start_time / duration);
goto found;
}
@@ -1999,27 +2154,44 @@ ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4,
entry++;
}
- ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
- "start time is out mp4 stts samples in \"%s\"",
- mp4->file.name.data);
+ if (start) {
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
+ "start time is out mp4 stts samples in \"%s\"",
+ mp4->file.name.data);
- return NGX_ERROR;
+ return NGX_ERROR;
+
+ } else {
+ trak->end_sample = trak->start_sample + start_sample;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "end_sample:%ui", trak->end_sample);
+
+ return NGX_OK;
+ }
found:
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
- "start_sample:%ui, new count:%uD", start_sample, count);
+ if (start) {
+ ngx_mp4_set_32value(entry->count, count - rest);
+ data->pos = (u_char *) entry;
+ trak->time_to_sample_entries = entries;
+ trak->start_sample = start_sample;
- trak->start_sample = start_sample;
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "start_sample:%ui, new count:%uD",
+ trak->start_sample, count - rest);
- data->pos = (u_char *) entry;
- atom_size = sizeof(ngx_mp4_stts_atom_t) + (data->last - data->pos);
- trak->size += atom_size;
+ } else {
+ ngx_mp4_set_32value(entry->count, rest);
+ data->last = (u_char *) (entry + 1);
+ trak->time_to_sample_entries -= entries - 1;
+ trak->end_sample = trak->start_sample + start_sample;
- atom = trak->out[NGX_HTTP_MP4_STTS_ATOM].buf;
- stts_atom = (ngx_mp4_stts_atom_t *) atom->pos;
- ngx_mp4_set_32value(stts_atom->size, atom_size);
- ngx_mp4_set_32value(stts_atom->entries, entries);
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "end_sample:%ui, new count:%uD",
+ trak->end_sample, rest);
+ }
return NGX_OK;
}
@@ -2101,7 +2273,7 @@ ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak)
{
size_t atom_size;
- uint32_t entries, sample, start_sample, *entry, *end;
+ uint32_t sample, start_sample, *entry, *end;
ngx_buf_t *atom, *data;
ngx_http_mp4_stss_atom_t *stss_atom;
@@ -2120,18 +2292,79 @@ ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4,
return NGX_OK;
}
+ ngx_http_mp4_crop_stss_data(mp4, trak, 1);
+ ngx_http_mp4_crop_stss_data(mp4, trak, 0);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "sync sample entries:%uD", trak->sync_samples_entries);
+
+ if (trak->sync_samples_entries) {
+ entry = (uint32_t *) data->pos;
+ end = (uint32_t *) data->last;
+
+ start_sample = trak->start_sample;
+
+ while (entry < end) {
+ sample = ngx_mp4_get_32value(entry);
+ sample -= start_sample;
+ ngx_mp4_set_32value(entry, sample);
+ entry++;
+ }
+
+ } else {
+ trak->out[NGX_HTTP_MP4_STSS_DATA].buf = NULL;
+ }
+
+ atom_size = sizeof(ngx_http_mp4_stss_atom_t) + (data->last - data->pos);
+ trak->size += atom_size;
+
+ atom = trak->out[NGX_HTTP_MP4_STSS_ATOM].buf;
+ stss_atom = (ngx_http_mp4_stss_atom_t *) atom->pos;
+
+ ngx_mp4_set_32value(stss_atom->size, atom_size);
+ ngx_mp4_set_32value(stss_atom->entries, trak->sync_samples_entries);
+
+ return NGX_OK;
+}
+
+
+static void
+ngx_http_mp4_crop_stss_data(ngx_http_mp4_file_t *mp4,
+ ngx_http_mp4_trak_t *trak, ngx_uint_t start)
+{
+ uint32_t sample, start_sample, *entry, *end;
+ ngx_buf_t *data;
+ ngx_uint_t entries;
+
/* sync samples starts from 1 */
- start_sample = trak->start_sample + 1;
- entries = trak->sync_samples_entries;
+ if (start) {
+ start_sample = trak->start_sample + 1;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "mp4 stss crop start_sample:%uD", start_sample);
+
+ } else if (mp4->length) {
+ start_sample = trak->end_sample + 1;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "mp4 stss crop end_sample:%uD", start_sample);
+
+ } else {
+ return;
+ }
+
+ data = trak->out[NGX_HTTP_MP4_STSS_DATA].buf;
+
+ entries = trak->sync_samples_entries;
entry = (uint32_t *) data->pos;
end = (uint32_t *) data->last;
while (entry < end) {
sample = ngx_mp4_get_32value(entry);
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
- "start:%uD, sync:%uD", start_sample, sample);
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "sync:%uD", sample);
if (sample >= start_sample) {
goto found;
@@ -2141,35 +2374,19 @@ ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4,
entry++;
}
- ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
- "start sample is out of mp4 stss atom in \"%s\"",
- mp4->file.name.data);
-
- return NGX_ERROR;
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "sample is out of mp4 stss atom");
found:
- data->pos = (u_char *) entry;
-
- start_sample = trak->start_sample;
+ if (start) {
+ data->pos = (u_char *) entry;
+ trak->sync_samples_entries = entries;
- while (entry < end) {
- sample = ngx_mp4_get_32value(entry);
- sample -= start_sample;
- ngx_mp4_set_32value(entry, sample);
- entry++;
+ } else {
+ data->last = (u_char *) entry;
+ trak->sync_samples_entries -= entries;
}
-
- atom_size = sizeof(ngx_http_mp4_stss_atom_t) + (data->last - data->pos);
- trak->size += atom_size;
-
- atom = trak->out[NGX_HTTP_MP4_STSS_ATOM].buf;
- stss_atom = (ngx_http_mp4_stss_atom_t *) atom->pos;
-
- ngx_mp4_set_32value(stss_atom->size, atom_size);
- ngx_mp4_set_32value(stss_atom->entries, entries);
-
- return NGX_OK;
}
@@ -2253,11 +2470,9 @@ static void
ngx_http_mp4_update_ctts_atom(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak)
{
- size_t atom_size;
- uint32_t entries, count, start_sample;
- ngx_buf_t *atom, *data;
- ngx_mp4_ctts_atom_t *ctts_atom;
- ngx_mp4_ctts_entry_t *entry, *end;
+ size_t atom_size;
+ ngx_buf_t *atom, *data;
+ ngx_mp4_ctts_atom_t *ctts_atom;
/*
* mdia.minf.stbl.ctts updating requires trak->start_sample
@@ -2274,8 +2489,61 @@ ngx_http_mp4_update_ctts_atom(ngx_http_mp4_file_t *mp4,
return;
}
+ ngx_http_mp4_crop_ctts_data(mp4, trak, 1);
+ ngx_http_mp4_crop_ctts_data(mp4, trak, 0);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "composition offset entries:%uD",
+ trak->composition_offset_entries);
+
+ if (trak->composition_offset_entries == 0) {
+ trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf = NULL;
+ trak->out[NGX_HTTP_MP4_CTTS_DATA].buf = NULL;
+ return;
+ }
+
+ atom_size = sizeof(ngx_mp4_ctts_atom_t) + (data->last - data->pos);
+ trak->size += atom_size;
+
+ atom = trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf;
+ ctts_atom = (ngx_mp4_ctts_atom_t *) atom->pos;
+
+ ngx_mp4_set_32value(ctts_atom->size, atom_size);
+ ngx_mp4_set_32value(ctts_atom->entries, trak->composition_offset_entries);
+
+ return;
+}
+
+
+static void
+ngx_http_mp4_crop_ctts_data(ngx_http_mp4_file_t *mp4,
+ ngx_http_mp4_trak_t *trak, ngx_uint_t start)
+{
+ uint32_t count, start_sample, rest;
+ ngx_buf_t *data;
+ ngx_uint_t entries;
+ ngx_mp4_ctts_entry_t *entry, *end;
+
/* sync samples starts from 1 */
- start_sample = trak->start_sample + 1;
+
+ if (start) {
+ start_sample = trak->start_sample + 1;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "mp4 ctts crop start_sample:%uD", start_sample);
+
+ } else if (mp4->length) {
+ start_sample = trak->end_sample - trak->start_sample + 1;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "mp4 ctts crop end_sample:%uD", start_sample);
+
+ } else {
+ return;
+ }
+
+ data = trak->out[NGX_HTTP_MP4_CTTS_DATA].buf;
+
entries = trak->composition_offset_entries;
entry = (ngx_mp4_ctts_entry_t *) data->pos;
end = (ngx_mp4_ctts_entry_t *) data->last;
@@ -2284,12 +2552,11 @@ ngx_http_mp4_update_ctts_atom(ngx_http_mp4_file_t *mp4,
count = ngx_mp4_get_32value(entry->count);
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
- "start:%uD, count:%uD, offset:%uD",
+ "sample:%uD, count:%uD, offset:%uD",
start_sample, count, ngx_mp4_get_32value(entry->offset));
if (start_sample <= count) {
- count -= (start_sample - 1);
- ngx_mp4_set_32value(entry->count, count);
+ rest = start_sample - 1;
goto found;
}
@@ -2298,24 +2565,25 @@ ngx_http_mp4_update_ctts_atom(ngx_http_mp4_file_t *mp4,
entry++;
}
- trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf = NULL;
- trak->out[NGX_HTTP_MP4_CTTS_DATA].buf = NULL;
+ if (start) {
+ data->pos = (u_char *) end;
+ trak->composition_offset_entries = 0;
+ }
return;
found:
- data->pos = (u_char *) entry;
- atom_size = sizeof(ngx_mp4_ctts_atom_t) + (data->last - data->pos);
- trak->size += atom_size;
-
- atom = trak->out[NGX_HTTP_MP4_CTTS_ATOM].buf;
- ctts_atom = (ngx_mp4_ctts_atom_t *) atom->pos;
+ if (start) {
+ ngx_mp4_set_32value(entry->count, count - rest);
+ data->pos = (u_char *) entry;
+ trak->composition_offset_entries = entries;
- ngx_mp4_set_32value(ctts_atom->size, atom_size);
- ngx_mp4_set_32value(ctts_atom->entries, entries);
-
- return;
+ } else {
+ ngx_mp4_set_32value(entry->count, rest);
+ data->last = (u_char *) (entry + 1);
+ trak->composition_offset_entries -= entries - 1;
+ }
}
@@ -2394,11 +2662,10 @@ ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak)
{
size_t atom_size;
- uint32_t start_sample, entries, chunk, samples, id,
- next_chunk, n;
- ngx_buf_t *atom, *data, *buf;
+ uint32_t chunk;
+ ngx_buf_t *atom, *data;
ngx_mp4_stsc_atom_t *stsc_atom;
- ngx_mp4_stsc_entry_t *entry, *first, *end;
+ ngx_mp4_stsc_entry_t *entry, *end;
/*
* mdia.minf.stbl.stsc updating requires trak->start_sample
@@ -2425,15 +2692,97 @@ ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4,
return NGX_ERROR;
}
- start_sample = (uint32_t) trak->start_sample;
+ if (ngx_http_mp4_crop_stsc_data(mp4, trak, 1) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ if (ngx_http_mp4_crop_stsc_data(mp4, trak, 0) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "sample-to-chunk entries:%uD",
+ trak->sample_to_chunk_entries);
+
+ entry = (ngx_mp4_stsc_entry_t *) data->pos;
+ end = (ngx_mp4_stsc_entry_t *) data->last;
+
+ while (entry < end) {
+ chunk = ngx_mp4_get_32value(entry->chunk);
+ chunk -= trak->start_chunk;
+ ngx_mp4_set_32value(entry->chunk, chunk);
+ entry++;
+ }
+
+ atom_size = sizeof(ngx_mp4_stsc_atom_t)
+ + trak->sample_to_chunk_entries * sizeof(ngx_mp4_stsc_entry_t);
+
+ trak->size += atom_size;
+
+ atom = trak->out[NGX_HTTP_MP4_STSC_ATOM].buf;
+ stsc_atom = (ngx_mp4_stsc_atom_t *) atom->pos;
+
+ ngx_mp4_set_32value(stsc_atom->size, atom_size);
+ ngx_mp4_set_32value(stsc_atom->entries, trak->sample_to_chunk_entries);
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_mp4_crop_stsc_data(ngx_http_mp4_file_t *mp4,
+ ngx_http_mp4_trak_t *trak, ngx_uint_t start)
+{
+ uint32_t start_sample, chunk, samples, id, next_chunk, n,
+ prev_samples;
+ ngx_buf_t *data, *buf;
+ ngx_uint_t entries, target_chunk, chunk_samples;
+ ngx_mp4_stsc_entry_t *entry, *end, *first;
+
entries = trak->sample_to_chunk_entries - 1;
+ if (start) {
+ start_sample = (uint32_t) trak->start_sample;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "mp4 stsc crop start_sample:%uD", start_sample);
+
+ } else if (mp4->length) {
+ start_sample = (uint32_t) (trak->end_sample - trak->start_sample);
+ samples = 0;
+
+ data = trak->out[NGX_HTTP_MP4_STSC_START].buf;
+
+ if (data) {
+ entry = (ngx_mp4_stsc_entry_t *) data->pos;
+ samples = ngx_mp4_get_32value(entry->samples);
+ entries--;
+
+ if (samples > start_sample) {
+ samples = start_sample;
+ ngx_mp4_set_32value(entry->samples, samples);
+ }
+
+ start_sample -= samples;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "mp4 stsc crop end_sample:%uD, ext_samples:%uD",
+ start_sample, samples);
+
+ } else {
+ return NGX_OK;
+ }
+
+ data = trak->out[NGX_HTTP_MP4_STSC_DATA].buf;
+
entry = (ngx_mp4_stsc_entry_t *) data->pos;
end = (ngx_mp4_stsc_entry_t *) data->last;
chunk = ngx_mp4_get_32value(entry->chunk);
samples = ngx_mp4_get_32value(entry->samples);
id = ngx_mp4_get_32value(entry->id);
+ prev_samples = 0;
entry++;
while (entry < end) {
@@ -2441,18 +2790,19 @@ ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4,
next_chunk = ngx_mp4_get_32value(entry->chunk);
ngx_log_debug5(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
- "start_sample:%uD, chunk:%uD, chunks:%uD, "
+ "sample:%uD, chunk:%uD, chunks:%uD, "
"samples:%uD, id:%uD",
start_sample, chunk, next_chunk - chunk, samples, id);
n = (next_chunk - chunk) * samples;
- if (start_sample <= n) {
+ if (start_sample < n) {
goto found;
}
start_sample -= n;
+ prev_samples = samples;
chunk = next_chunk;
samples = ngx_mp4_get_32value(entry->samples);
id = ngx_mp4_get_32value(entry->id);
@@ -2460,18 +2810,18 @@ ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4,
entry++;
}
- next_chunk = trak->chunks;
+ next_chunk = trak->chunks + 1;
ngx_log_debug4(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
- "start_sample:%uD, chunk:%uD, chunks:%uD, samples:%uD",
+ "sample:%uD, chunk:%uD, chunks:%uD, samples:%uD",
start_sample, chunk, next_chunk - chunk, samples);
n = (next_chunk - chunk) * samples;
if (start_sample > n) {
ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
- "start time is out mp4 stsc chunks in \"%s\"",
- mp4->file.name.data);
+ "%s time is out mp4 stsc chunks in \"%s\"",
+ start ? "start" : "end", mp4->file.name.data);
return NGX_ERROR;
}
@@ -2487,59 +2837,91 @@ found:
return NGX_ERROR;
}
- trak->start_chunk = chunk - 1;
+ target_chunk = chunk - 1;
+ target_chunk += start_sample / samples;
+ chunk_samples = start_sample % samples;
- trak->start_chunk += start_sample / samples;
- trak->chunk_samples = start_sample % samples;
+ if (start) {
+ data->pos = (u_char *) entry;
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
- "start chunk:%ui, samples:%uD",
- trak->start_chunk, trak->chunk_samples);
+ trak->sample_to_chunk_entries = entries;
+ trak->start_chunk = target_chunk;
+ trak->start_chunk_samples = chunk_samples;
+
+ ngx_mp4_set_32value(entry->chunk, trak->start_chunk + 1);
+
+ samples -= chunk_samples;
- data->pos = (u_char *) entry;
- atom_size = sizeof(ngx_mp4_stsc_atom_t) + (data->last - data->pos);
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "start_chunk:%ui, start_chunk_samples:%ui",
+ trak->start_chunk, trak->start_chunk_samples);
+
+ } else {
+ if (start_sample) {
+ data->last = (u_char *) (entry + 1);
+ trak->sample_to_chunk_entries -= entries - 1;
+ trak->end_chunk_samples = samples;
- ngx_mp4_set_32value(entry->chunk, 1);
+ } else {
+ data->last = (u_char *) entry;
+ trak->sample_to_chunk_entries -= entries;
+ trak->end_chunk_samples = prev_samples;
+ }
- if (trak->chunk_samples && next_chunk - trak->start_chunk == 2) {
+ if (chunk_samples) {
+ trak->end_chunk = target_chunk + 1;
+ trak->end_chunk_samples = chunk_samples;
- /* last chunk in the entry */
+ } else {
+ trak->end_chunk = target_chunk;
+ }
- ngx_mp4_set_32value(entry->samples, samples - trak->chunk_samples);
+ samples = chunk_samples;
+ next_chunk = chunk + 1;
- } else if (trak->chunk_samples) {
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "end_chunk:%ui, end_chunk_samples:%ui",
+ trak->end_chunk, trak->end_chunk_samples);
+ }
- first = &trak->stsc_chunk_entry;
+ if (chunk_samples && next_chunk - target_chunk == 2) {
+
+ ngx_mp4_set_32value(entry->samples, samples);
+
+ } else if (chunk_samples && start) {
+
+ first = &trak->stsc_start_chunk_entry;
ngx_mp4_set_32value(first->chunk, 1);
- ngx_mp4_set_32value(first->samples, samples - trak->chunk_samples);
+ ngx_mp4_set_32value(first->samples, samples);
ngx_mp4_set_32value(first->id, id);
- buf = &trak->stsc_chunk_buf;
+ buf = &trak->stsc_start_chunk_buf;
buf->temporary = 1;
buf->pos = (u_char *) first;
buf->last = (u_char *) first + sizeof(ngx_mp4_stsc_entry_t);
- trak->out[NGX_HTTP_MP4_STSC_CHUNK].buf = buf;
+ trak->out[NGX_HTTP_MP4_STSC_START].buf = buf;
- ngx_mp4_set_32value(entry->chunk, 2);
+ ngx_mp4_set_32value(entry->chunk, trak->start_chunk + 2);
- entries++;
- atom_size += sizeof(ngx_mp4_stsc_entry_t);
- }
+ trak->sample_to_chunk_entries++;
- while (++entry < end) {
- chunk = ngx_mp4_get_32value(entry->chunk);
- chunk -= trak->start_chunk;
- ngx_mp4_set_32value(entry->chunk, chunk);
- }
+ } else if (chunk_samples) {
- trak->size += atom_size;
+ first = &trak->stsc_end_chunk_entry;
+ ngx_mp4_set_32value(first->chunk, trak->end_chunk - trak->start_chunk);
+ ngx_mp4_set_32value(first->samples, samples);
+ ngx_mp4_set_32value(first->id, id);
- atom = trak->out[NGX_HTTP_MP4_STSC_ATOM].buf;
- stsc_atom = (ngx_mp4_stsc_atom_t *) atom->pos;
+ buf = &trak->stsc_end_chunk_buf;
+ buf->temporary = 1;
+ buf->pos = (u_char *) first;
+ buf->last = (u_char *) first + sizeof(ngx_mp4_stsc_entry_t);
- ngx_mp4_set_32value(stsc_atom->size, atom_size);
- ngx_mp4_set_32value(stsc_atom->entries, entries);
+ trak->out[NGX_HTTP_MP4_STSC_END].buf = buf;
+
+ trak->sample_to_chunk_entries++;
+ }
return NGX_OK;
}
@@ -2635,7 +3017,7 @@ ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak)
{
size_t atom_size;
- uint32_t *pos, *end;
+ uint32_t *pos, *end, entries;
ngx_buf_t *atom, *data;
ngx_mp4_stsz_atom_t *stsz_atom;
@@ -2651,22 +3033,47 @@ ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4,
data = trak->out[NGX_HTTP_MP4_STSZ_DATA].buf;
if (data) {
- if (trak->start_sample > trak->sample_sizes_entries) {
+ entries = trak->sample_sizes_entries;
+
+ if (trak->start_sample > entries) {
ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
"start time is out mp4 stsz samples in \"%s\"",
mp4->file.name.data);
return NGX_ERROR;
}
+ entries -= trak->start_sample;
data->pos += trak->start_sample * sizeof(uint32_t);
end = (uint32_t *) data->pos;
- for (pos = end - trak->chunk_samples; pos < end; pos++) {
- trak->chunk_samples_size += ngx_mp4_get_32value(pos);
+ for (pos = end - trak->start_chunk_samples; pos < end; pos++) {
+ trak->start_chunk_samples_size += ngx_mp4_get_32value(pos);
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
- "chunk samples sizes:%uL", trak->chunk_samples_size);
+ "chunk samples sizes:%uL",
+ trak->start_chunk_samples_size);
+
+ if (mp4->length) {
+ if (trak->end_sample - trak->start_sample > entries) {
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
+ "end time is out mp4 stsz samples in \"%s\"",
+ mp4->file.name.data);
+ return NGX_ERROR;
+ }
+
+ entries = trak->end_sample - trak->start_sample;
+ data->last = data->pos + entries * sizeof(uint32_t);
+ end = (uint32_t *) data->last;
+
+ for (pos = end - trak->end_chunk_samples; pos < end; pos++) {
+ trak->end_chunk_samples_size += ngx_mp4_get_32value(pos);
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "mp4 stsz end_chunk_samples_size:%uL",
+ trak->end_chunk_samples_size);
+ }
atom_size = sizeof(ngx_mp4_stsz_atom_t) + (data->last - data->pos);
trak->size += atom_size;
@@ -2675,8 +3082,7 @@ ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4,
stsz_atom = (ngx_mp4_stsz_atom_t *) atom->pos;
ngx_mp4_set_32value(stsz_atom->size, atom_size);
- ngx_mp4_set_32value(stsz_atom->entries,
- trak->sample_sizes_entries - trak->start_sample);
+ ngx_mp4_set_32value(stsz_atom->entries, entries);
}
return NGX_OK;
@@ -2757,6 +3163,7 @@ ngx_http_mp4_update_stco_atom(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak)
{
size_t atom_size;
+ uint32_t entries;
ngx_buf_t *atom, *data;
ngx_mp4_stco_atom_t *stco_atom;
@@ -2786,21 +3193,53 @@ ngx_http_mp4_update_stco_atom(ngx_http_mp4_file_t *mp4,
}
data->pos += trak->start_chunk * sizeof(uint32_t);
- atom_size = sizeof(ngx_mp4_stco_atom_t) + (data->last - data->pos);
- trak->size += atom_size;
trak->start_offset = ngx_mp4_get_32value(data->pos);
- trak->start_offset += trak->chunk_samples_size;
+ trak->start_offset += trak->start_chunk_samples_size;
ngx_mp4_set_32value(data->pos, trak->start_offset);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
- "start chunk offset:%uD", trak->start_offset);
+ "start chunk offset:%O", trak->start_offset);
+
+ if (mp4->length) {
+
+ if (trak->end_chunk > trak->chunks) {
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
+ "end time is out mp4 stco chunks in \"%s\"",
+ mp4->file.name.data);
+ return NGX_ERROR;
+ }
+
+ entries = trak->end_chunk - trak->start_chunk;
+ data->last = data->pos + entries * sizeof(uint32_t);
+
+ if (entries) {
+ trak->end_offset =
+ ngx_mp4_get_32value(data->last - sizeof(uint32_t));
+ trak->end_offset += trak->end_chunk_samples_size;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "end chunk offset:%O", trak->end_offset);
+ }
+
+ } else {
+ entries = trak->chunks - trak->start_chunk;
+ trak->end_offset = mp4->mdat_data.buf->file_last;
+ }
+
+ if (entries == 0) {
+ trak->start_offset = mp4->end;
+ trak->end_offset = 0;
+ }
+
+ atom_size = sizeof(ngx_mp4_stco_atom_t) + (data->last - data->pos);
+ trak->size += atom_size;
atom = trak->out[NGX_HTTP_MP4_STCO_ATOM].buf;
stco_atom = (ngx_mp4_stco_atom_t *) atom->pos;
ngx_mp4_set_32value(stco_atom->size, atom_size);
- ngx_mp4_set_32value(stco_atom->entries, trak->chunks - trak->start_chunk);
+ ngx_mp4_set_32value(stco_atom->entries, entries);
return NGX_OK;
}
@@ -2908,6 +3347,7 @@ ngx_http_mp4_update_co64_atom(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak)
{
size_t atom_size;
+ uint64_t entries;
ngx_buf_t *atom, *data;
ngx_mp4_co64_atom_t *co64_atom;
@@ -2937,21 +3377,53 @@ ngx_http_mp4_update_co64_atom(ngx_http_mp4_file_t *mp4,
}
data->pos += trak->start_chunk * sizeof(uint64_t);
- atom_size = sizeof(ngx_mp4_co64_atom_t) + (data->last - data->pos);
- trak->size += atom_size;
trak->start_offset = ngx_mp4_get_64value(data->pos);
- trak->start_offset += trak->chunk_samples_size;
+ trak->start_offset += trak->start_chunk_samples_size;
ngx_mp4_set_64value(data->pos, trak->start_offset);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
- "start chunk offset:%uL", trak->start_offset);
+ "start chunk offset:%O", trak->start_offset);
+
+ if (mp4->length) {
+
+ if (trak->end_chunk > trak->chunks) {
+ ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
+ "end time is out mp4 co64 chunks in \"%s\"",
+ mp4->file.name.data);
+ return NGX_ERROR;
+ }
+
+ entries = trak->end_chunk - trak->start_chunk;
+ data->last = data->pos + entries * sizeof(uint64_t);
+
+ if (entries) {
+ trak->end_offset =
+ ngx_mp4_get_64value(data->last - sizeof(uint64_t));
+ trak->end_offset += trak->end_chunk_samples_size;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
+ "end chunk offset:%O", trak->end_offset);
+ }
+
+ } else {
+ entries = trak->chunks - trak->start_chunk;
+ trak->end_offset = mp4->mdat_data.buf->file_last;
+ }
+
+ if (entries == 0) {
+ trak->start_offset = mp4->end;
+ trak->end_offset = 0;
+ }
+
+ atom_size = sizeof(ngx_mp4_co64_atom_t) + (data->last - data->pos);
+ trak->size += atom_size;
atom = trak->out[NGX_HTTP_MP4_CO64_ATOM].buf;
co64_atom = (ngx_mp4_co64_atom_t *) atom->pos;
ngx_mp4_set_32value(co64_atom->size, atom_size);
- ngx_mp4_set_32value(co64_atom->entries, trak->chunks - trak->start_chunk);
+ ngx_mp4_set_32value(co64_atom->entries, entries);
return NGX_OK;
}
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_proxy_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_proxy_module.c
index 5e62caa30f4..8ee32f491a1 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_proxy_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_proxy_module.c
@@ -76,6 +76,12 @@ typedef struct {
ngx_uint_t headers_hash_max_size;
ngx_uint_t headers_hash_bucket_size;
+
+#if (NGX_HTTP_SSL)
+ ngx_uint_t ssl;
+ ngx_uint_t ssl_protocols;
+ ngx_str_t ssl_ciphers;
+#endif
} ngx_http_proxy_loc_conf_t;
@@ -178,6 +184,7 @@ static ngx_conf_bitmask_t ngx_http_proxy_next_upstream_masks[] = {
{ ngx_string("http_502"), NGX_HTTP_UPSTREAM_FT_HTTP_502 },
{ ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
{ ngx_string("http_504"), NGX_HTTP_UPSTREAM_FT_HTTP_504 },
+ { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 },
{ ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
{ ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING },
{ ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
@@ -185,6 +192,20 @@ static ngx_conf_bitmask_t ngx_http_proxy_next_upstream_masks[] = {
};
+#if (NGX_HTTP_SSL)
+
+static ngx_conf_bitmask_t ngx_http_proxy_ssl_protocols[] = {
+ { ngx_string("SSLv2"), NGX_SSL_SSLv2 },
+ { ngx_string("SSLv3"), NGX_SSL_SSLv3 },
+ { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
+ { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 },
+ { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 },
+ { ngx_null_string, 0 }
+};
+
+#endif
+
+
static ngx_conf_enum_t ngx_http_proxy_http_version[] = {
{ ngx_string("1.0"), NGX_HTTP_VERSION_10 },
{ ngx_string("1.1"), NGX_HTTP_VERSION_11 },
@@ -444,6 +465,13 @@ static ngx_command_t ngx_http_proxy_commands[] = {
offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock_timeout),
NULL },
+ { ngx_string("proxy_cache_revalidate"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_revalidate),
+ NULL },
+
#endif
{ ngx_string("proxy_temp_path"),
@@ -511,6 +539,20 @@ static ngx_command_t ngx_http_proxy_commands[] = {
offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_session_reuse),
NULL },
+ { ngx_string("proxy_ssl_protocols"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+ ngx_conf_set_bitmask_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, ssl_protocols),
+ &ngx_http_proxy_ssl_protocols },
+
+ { ngx_string("proxy_ssl_ciphers"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, ssl_ciphers),
+ NULL },
+
#endif
ngx_null_command
@@ -587,7 +629,8 @@ static ngx_keyval_t ngx_http_proxy_cache_headers[] = {
{ ngx_string("Keep-Alive"), ngx_string("") },
{ ngx_string("Expect"), ngx_string("") },
{ ngx_string("Upgrade"), ngx_string("") },
- { ngx_string("If-Modified-Since"), ngx_string("") },
+ { ngx_string("If-Modified-Since"),
+ ngx_string("$upstream_cache_last_modified") },
{ ngx_string("If-Unmodified-Since"), ngx_string("") },
{ ngx_string("If-None-Match"), ngx_string("") },
{ ngx_string("If-Match"), ngx_string("") },
@@ -993,6 +1036,8 @@ ngx_http_proxy_create_request(ngx_http_request_t *r)
len += uri_len;
+ ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
+
ngx_http_script_flush_no_cacheable_variables(r, plcf->flushes);
if (plcf->body_set_len) {
@@ -1317,7 +1362,7 @@ ngx_http_proxy_process_status_line(ngx_http_request_t *r)
return NGX_OK;
}
- if (u->state) {
+ if (u->state && u->state->status == 0) {
u->state->status = ctx->status.code;
}
@@ -1539,7 +1584,7 @@ ngx_http_proxy_input_filter_init(void *data)
u->pipe->length = 3; /* "0" LF LF */
u->input_filter = ngx_http_proxy_non_buffered_chunked_filter;
- u->length = -1;
+ u->length = 1;
} else if (u->headers_in.content_length_n == 0) {
/* empty body: special case as filter won't be called */
@@ -1570,19 +1615,13 @@ ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
return NGX_OK;
}
- if (p->free) {
- cl = p->free;
- b = cl->buf;
- p->free = cl->next;
- ngx_free_chain(p->pool, cl);
-
- } else {
- b = ngx_alloc_buf(p->pool);
- if (b == NULL) {
- return NGX_ERROR;
- }
+ cl = ngx_chain_get_free_buf(p->pool, &p->free);
+ if (cl == NULL) {
+ return NGX_ERROR;
}
+ b = cl->buf;
+
ngx_memcpy(b, buf, sizeof(ngx_buf_t));
b->shadow = buf;
b->tag = p->tag;
@@ -1590,14 +1629,6 @@ ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
b->recycled = 1;
buf->shadow = b;
- cl = ngx_alloc_chain_link(p->pool);
- if (cl == NULL) {
- return NGX_ERROR;
- }
-
- cl->buf = b;
- cl->next = NULL;
-
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num);
if (p->in) {
@@ -1662,19 +1693,13 @@ ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
/* a chunk has been parsed successfully */
- if (p->free) {
- cl = p->free;
- b = cl->buf;
- p->free = cl->next;
- ngx_free_chain(p->pool, cl);
-
- } else {
- b = ngx_alloc_buf(p->pool);
- if (b == NULL) {
- return NGX_ERROR;
- }
+ cl = ngx_chain_get_free_buf(p->pool, &p->free);
+ if (cl == NULL) {
+ return NGX_ERROR;
}
+ b = cl->buf;
+
ngx_memzero(b, sizeof(ngx_buf_t));
b->pos = buf->pos;
@@ -1687,14 +1712,6 @@ ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
*prev = b;
prev = &b->shadow;
- cl = ngx_alloc_chain_link(p->pool);
- if (cl == NULL) {
- return NGX_ERROR;
- }
-
- cl->buf = b;
- cl->next = NULL;
-
if (p->in) {
*p->last_in = cl;
} else {
@@ -1709,7 +1726,7 @@ ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
if (buf->last - buf->pos >= ctx->chunked.size) {
- buf->pos += ctx->chunked.size;
+ buf->pos += (size_t) ctx->chunked.size;
b->last = buf->pos;
ctx->chunked.size = 0;
@@ -1872,7 +1889,7 @@ ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes)
b->tag = u->output.tag;
if (buf->last - buf->pos >= ctx->chunked.size) {
- buf->pos += ctx->chunked.size;
+ buf->pos += (size_t) ctx->chunked.size;
b->last = buf->pos;
ctx->chunked.size = 0;
@@ -2077,7 +2094,7 @@ ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
v->no_cacheable = 0;
v->not_found = 0;
- v->data = ngx_pnalloc(r->connection->pool, NGX_OFF_T_LEN);
+ v->data = ngx_pnalloc(r->pool, NGX_OFF_T_LEN);
if (v->data == NULL) {
return NGX_ERROR;
@@ -2383,6 +2400,9 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
* conf->body_set = NULL;
* conf->body_source = { 0, NULL };
* conf->redirects = NULL;
+ * conf->ssl = 0;
+ * conf->ssl_protocols = 0;
+ * conf->ssl_ciphers = { 0, NULL };
*/
conf->upstream.store = NGX_CONF_UNSET;
@@ -2414,6 +2434,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
conf->upstream.cache_lock = NGX_CONF_UNSET;
conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
+ conf->upstream.cache_revalidate = NGX_CONF_UNSET;
#endif
conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
@@ -2657,12 +2678,6 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_ptr_value(conf->upstream.no_cache,
prev->upstream.no_cache, NULL);
- if (conf->upstream.no_cache && conf->upstream.cache_bypass == NULL) {
- ngx_log_error(NGX_LOG_WARN, cf->log, 0,
- "\"proxy_no_cache\" functionality has been changed in 0.8.46, "
- "now it should be used together with \"proxy_cache_bypass\"");
- }
-
ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
prev->upstream.cache_valid, NULL);
@@ -2676,6 +2691,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
prev->upstream.cache_lock_timeout, 5000);
+ ngx_conf_merge_value(conf->upstream.cache_revalidate,
+ prev->upstream.cache_revalidate, 0);
+
#endif
ngx_conf_merge_str_value(conf->method, prev->method, "");
@@ -2698,6 +2716,18 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
#if (NGX_HTTP_SSL)
ngx_conf_merge_value(conf->upstream.ssl_session_reuse,
prev->upstream.ssl_session_reuse, 1);
+
+ ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols,
+ (NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3
+ |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1
+ |NGX_SSL_TLSv1_2));
+
+ ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers,
+ "DEFAULT");
+
+ if (conf->ssl && ngx_http_proxy_set_ssl(cf, conf) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
#endif
ngx_conf_merge_value(conf->redirect, prev->redirect, 1);
@@ -3143,9 +3173,7 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}
#if (NGX_HTTP_SSL)
- if (ngx_http_proxy_set_ssl(cf, plcf) != NGX_OK) {
- return NGX_CONF_ERROR;
- }
+ plcf->ssl = 1;
#endif
return NGX_CONF_OK;
@@ -3158,9 +3186,7 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
} else if (ngx_strncasecmp(url->data, (u_char *) "https://", 8) == 0) {
#if (NGX_HTTP_SSL)
- if (ngx_http_proxy_set_ssl(cf, plcf) != NGX_OK) {
- return NGX_CONF_ERROR;
- }
+ plcf->ssl = 1;
add = 8;
port = 443;
@@ -3742,15 +3768,22 @@ ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf)
plcf->upstream.ssl->log = cf->log;
- if (ngx_ssl_create(plcf->upstream.ssl,
- NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1
- |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2,
- NULL)
+ if (ngx_ssl_create(plcf->upstream.ssl, plcf->ssl_protocols, NULL)
!= NGX_OK)
{
return NGX_ERROR;
}
+ if (SSL_CTX_set_cipher_list(plcf->upstream.ssl->ctx,
+ (const char *) plcf->ssl_ciphers.data)
+ == 0)
+ {
+ ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
+ "SSL_CTX_set_cipher_list(\"%V\") failed",
+ &plcf->ssl_ciphers);
+ return NGX_ERROR;
+ }
+
cln = ngx_pool_cleanup_add(cf->pool, 0);
if (cln == NULL) {
return NGX_ERROR;
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_range_filter_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_range_filter_module.c
index 82c202d33c5..6a65e48498d 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_range_filter_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_range_filter_module.c
@@ -22,7 +22,7 @@
* ... data ...
*
*
- * the mutlipart format:
+ * the multipart format:
*
* "HTTP/1.0 206 Partial Content" CRLF
* ... header ...
@@ -148,6 +148,7 @@ ngx_http_range_header_filter(ngx_http_request_t *r)
{
time_t if_range_time;
ngx_str_t *if_range, *etag;
+ ngx_uint_t ranges;
ngx_http_core_loc_conf_t *clcf;
ngx_http_range_filter_ctx_t *ctx;
@@ -227,7 +228,9 @@ parse:
return NGX_ERROR;
}
- switch (ngx_http_range_parse(r, ctx, clcf->max_ranges)) {
+ ranges = r->single_range ? 1 : clcf->max_ranges;
+
+ switch (ngx_http_range_parse(r, ctx, ranges)) {
case NGX_OK:
ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module);
@@ -432,7 +435,9 @@ ngx_http_range_multipart_header(ngx_http_request_t *r,
+ r->headers_out.content_type.len
+ sizeof(CRLF "Content-Range: bytes ") - 1;
- if (r->headers_out.charset.len) {
+ if (r->headers_out.content_type_len == r->headers_out.content_type.len
+ && r->headers_out.charset.len)
+ {
len += sizeof("; charset=") - 1 + r->headers_out.charset.len;
}
@@ -451,7 +456,9 @@ ngx_http_range_multipart_header(ngx_http_request_t *r,
* "Content-Range: bytes "
*/
- if (r->headers_out.charset.len) {
+ if (r->headers_out.content_type_len == r->headers_out.content_type.len
+ && r->headers_out.charset.len)
+ {
ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data,
CRLF "--%0muA" CRLF
"Content-Type: %V; charset=%V" CRLF
@@ -461,8 +468,6 @@ ngx_http_range_multipart_header(ngx_http_request_t *r,
&r->headers_out.charset)
- ctx->boundary_header.data;
- r->headers_out.charset.len = 0;
-
} else if (r->headers_out.content_type.len) {
ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data,
CRLF "--%0muA" CRLF
@@ -501,6 +506,8 @@ ngx_http_range_multipart_header(ngx_http_request_t *r,
r->headers_out.content_type_len = r->headers_out.content_type.len;
+ r->headers_out.charset.len = 0;
+
/* the size of the last boundary CRLF "--0123456789--" CRLF */
len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN + sizeof("--" CRLF) - 1;
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_realip_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_realip_module.c
index ed9c5f9e82c..7a621180379 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_realip_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_realip_module.c
@@ -13,6 +13,7 @@
#define NGX_HTTP_REALIP_XREALIP 0
#define NGX_HTTP_REALIP_XFWD 1
#define NGX_HTTP_REALIP_HEADER 2
+#define NGX_HTTP_REALIP_PROXY 3
typedef struct {
@@ -156,6 +157,18 @@ ngx_http_realip_handler(ngx_http_request_t *r)
break;
+ case NGX_HTTP_REALIP_PROXY:
+
+ value = &r->connection->proxy_protocol_addr;
+
+ if (value->len == 0) {
+ return NGX_DECLINED;
+ }
+
+ xfwd = NULL;
+
+ break;
+
default: /* NGX_HTTP_REALIP_HEADER */
part = &r->headers_in.headers.part;
@@ -230,7 +243,8 @@ ngx_http_realip_set_addr(ngx_http_request_t *r, ngx_addr_t *addr)
c = r->connection;
- len = ngx_sock_ntop(addr->sockaddr, text, NGX_SOCKADDR_STRLEN, 0);
+ len = ngx_sock_ntop(addr->sockaddr, addr->socklen, text,
+ NGX_SOCKADDR_STRLEN, 0);
if (len == 0) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
@@ -342,6 +356,11 @@ ngx_http_realip(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return NGX_CONF_OK;
}
+ if (ngx_strcmp(value[1].data, "proxy_protocol") == 0) {
+ rlcf->type = NGX_HTTP_REALIP_PROXY;
+ return NGX_CONF_OK;
+ }
+
rlcf->type = NGX_HTTP_REALIP_HEADER;
rlcf->hash = ngx_hash_strlow(value[1].data, value[1].data, value[1].len);
rlcf->header = value[1];
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_referer_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_referer_module.c
index d8a014c5be6..b417eb227b0 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_referer_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_referer_module.c
@@ -12,22 +12,18 @@
#define NGX_HTTP_REFERER_NO_URI_PART ((void *) 4)
-#if !(NGX_PCRE)
-
-#define ngx_regex_t void
-
-#endif
-
typedef struct {
ngx_hash_combined_t hash;
#if (NGX_PCRE)
ngx_array_t *regex;
+ ngx_array_t *server_name_regex;
#endif
ngx_flag_t no_referer;
ngx_flag_t blocked_referer;
+ ngx_flag_t server_names;
ngx_hash_keys_arrays_t *keys;
@@ -41,10 +37,14 @@ static char * ngx_http_referer_merge_conf(ngx_conf_t *cf, void *parent,
void *child);
static char *ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
-static char *ngx_http_add_referer(ngx_conf_t *cf, ngx_hash_keys_arrays_t *keys,
- ngx_str_t *value, ngx_str_t *uri);
-static char *ngx_http_add_regex_referer(ngx_conf_t *cf,
- ngx_http_referer_conf_t *rlcf, ngx_str_t *name, ngx_regex_t *regex);
+static ngx_int_t ngx_http_add_referer(ngx_conf_t *cf,
+ ngx_hash_keys_arrays_t *keys, ngx_str_t *value, ngx_str_t *uri);
+static ngx_int_t ngx_http_add_regex_referer(ngx_conf_t *cf,
+ ngx_http_referer_conf_t *rlcf, ngx_str_t *name);
+#if (NGX_PCRE)
+static ngx_int_t ngx_http_add_regex_server_name(ngx_conf_t *cf,
+ ngx_http_referer_conf_t *rlcf, ngx_http_regex_t *regex);
+#endif
static int ngx_libc_cdecl ngx_http_cmp_referer_wildcards(const void *one,
const void *two);
@@ -117,6 +117,10 @@ ngx_http_referer_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
ngx_uint_t i, key;
ngx_http_referer_conf_t *rlcf;
u_char buf[256];
+#if (NGX_PCRE)
+ ngx_int_t rc;
+ ngx_str_t referer;
+#endif
rlcf = ngx_http_get_module_loc_conf(r, ngx_http_referer_module);
@@ -125,6 +129,7 @@ ngx_http_referer_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
&& rlcf->hash.wc_tail == NULL
#if (NGX_PCRE)
&& rlcf->regex == NULL
+ && rlcf->server_name_regex == NULL
#endif
)
{
@@ -147,10 +152,12 @@ ngx_http_referer_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
if (ngx_strncasecmp(ref, (u_char *) "http://", 7) == 0) {
ref += 7;
+ len -= 7;
goto valid_scheme;
} else if (ngx_strncasecmp(ref, (u_char *) "https://", 8) == 0) {
ref += 8;
+ len -= 8;
goto valid_scheme;
}
}
@@ -171,12 +178,12 @@ valid_scheme:
break;
}
- buf[i] = ngx_tolower(*p);
- key = ngx_hash(key, buf[i++]);
-
if (i == 256) {
goto invalid;
}
+
+ buf[i] = ngx_tolower(*p);
+ key = ngx_hash(key, buf[i++]);
}
uri = ngx_hash_find_combined(&rlcf->hash, key, buf, p - ref);
@@ -187,11 +194,26 @@ valid_scheme:
#if (NGX_PCRE)
- if (rlcf->regex) {
- ngx_int_t rc;
- ngx_str_t referer;
+ if (rlcf->server_name_regex) {
+ referer.len = p - ref;
+ referer.data = buf;
+
+ rc = ngx_regex_exec_array(rlcf->server_name_regex, &referer,
+ r->connection->log);
+
+ if (rc == NGX_OK) {
+ goto valid;
+ }
+
+ if (rc == NGX_ERROR) {
+ return rc;
+ }
+
+ /* NGX_DECLINED */
+ }
- referer.len = len - 7;
+ if (rlcf->regex) {
+ referer.len = len;
referer.data = ref;
rc = ngx_regex_exec_array(rlcf->regex, &referer, r->connection->log);
@@ -251,8 +273,17 @@ ngx_http_referer_create_conf(ngx_conf_t *cf)
return NULL;
}
+ /*
+ * set by ngx_pcalloc():
+ *
+ * conf->hash = { NULL };
+ * conf->server_names = 0;
+ * conf->keys = NULL;
+ */
+
#if (NGX_PCRE)
conf->regex = NGX_CONF_UNSET_PTR;
+ conf->server_name_regex = NGX_CONF_UNSET_PTR;
#endif
conf->no_referer = NGX_CONF_UNSET;
@@ -270,13 +301,18 @@ ngx_http_referer_merge_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_http_referer_conf_t *prev = parent;
ngx_http_referer_conf_t *conf = child;
- ngx_hash_init_t hash;
+ ngx_uint_t n;
+ ngx_hash_init_t hash;
+ ngx_http_server_name_t *sn;
+ ngx_http_core_srv_conf_t *cscf;
if (conf->keys == NULL) {
conf->hash = prev->hash;
#if (NGX_PCRE)
ngx_conf_merge_ptr_value(conf->regex, prev->regex, NULL);
+ ngx_conf_merge_ptr_value(conf->server_name_regex,
+ prev->server_name_regex, NULL);
#endif
ngx_conf_merge_value(conf->no_referer, prev->no_referer, 0);
ngx_conf_merge_value(conf->blocked_referer, prev->blocked_referer, 0);
@@ -288,6 +324,33 @@ ngx_http_referer_merge_conf(ngx_conf_t *cf, void *parent, void *child)
return NGX_CONF_OK;
}
+ if (conf->server_names == 1) {
+ cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module);
+
+ sn = cscf->server_names.elts;
+ for (n = 0; n < cscf->server_names.nelts; n++) {
+
+#if (NGX_PCRE)
+ if (sn[n].regex) {
+
+ if (ngx_http_add_regex_server_name(cf, conf, sn[n].regex)
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
+
+ continue;
+ }
+#endif
+
+ if (ngx_http_add_referer(cf, conf->keys, &sn[n].name, NULL)
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
+ }
+ }
+
if ((conf->no_referer == 1 || conf->blocked_referer == 1)
&& conf->keys->keys.nelts == 0
&& conf->keys->dns_wc_head.nelts == 0
@@ -366,6 +429,8 @@ ngx_http_referer_merge_conf(ngx_conf_t *cf, void *parent, void *child)
#if (NGX_PCRE)
ngx_conf_merge_ptr_value(conf->regex, prev->regex, NULL);
+ ngx_conf_merge_ptr_value(conf->server_name_regex, prev->server_name_regex,
+ NULL);
#endif
if (conf->no_referer == NGX_CONF_UNSET) {
@@ -389,15 +454,12 @@ ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
u_char *p;
ngx_str_t *value, uri, name;
- ngx_uint_t i, n;
+ ngx_uint_t i;
ngx_http_variable_t *var;
- ngx_http_server_name_t *sn;
- ngx_http_core_srv_conf_t *cscf;
ngx_str_set(&name, "invalid_referer");
- var = ngx_http_add_variable(cf, &name,
- NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOHASH);
+ var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE);
if (var == NULL) {
return NGX_CONF_ERROR;
}
@@ -437,48 +499,21 @@ ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
continue;
}
- ngx_str_null(&uri);
-
if (ngx_strcmp(value[i].data, "server_names") == 0) {
-
- cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module);
-
- sn = cscf->server_names.elts;
- for (n = 0; n < cscf->server_names.nelts; n++) {
-
-#if (NGX_PCRE)
- if (sn[n].regex) {
-
- if (ngx_http_add_regex_referer(cf, rlcf, &sn[n].name,
- sn[n].regex->regex)
- != NGX_OK)
- {
- return NGX_CONF_ERROR;
- }
-
- continue;
- }
-#endif
-
- if (ngx_http_add_referer(cf, rlcf->keys, &sn[n].name, &uri)
- != NGX_OK)
- {
- return NGX_CONF_ERROR;
- }
- }
-
+ rlcf->server_names = 1;
continue;
}
if (value[i].data[0] == '~') {
- if (ngx_http_add_regex_referer(cf, rlcf, &value[i], NULL) != NGX_OK)
- {
+ if (ngx_http_add_regex_referer(cf, rlcf, &value[i]) != NGX_OK) {
return NGX_CONF_ERROR;
}
continue;
}
+ ngx_str_null(&uri);
+
p = (u_char *) ngx_strchr(value[i].data, '/');
if (p) {
@@ -496,20 +531,20 @@ ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}
-static char *
+static ngx_int_t
ngx_http_add_referer(ngx_conf_t *cf, ngx_hash_keys_arrays_t *keys,
ngx_str_t *value, ngx_str_t *uri)
{
ngx_int_t rc;
ngx_str_t *u;
- if (uri->len == 0) {
+ if (uri == NULL || uri->len == 0) {
u = NGX_HTTP_REFERER_NO_URI_PART;
} else {
u = ngx_palloc(cf->pool, sizeof(ngx_str_t));
if (u == NULL) {
- return NGX_CONF_ERROR;
+ return NGX_ERROR;
}
*u = *uri;
@@ -518,7 +553,7 @@ ngx_http_add_referer(ngx_conf_t *cf, ngx_hash_keys_arrays_t *keys,
rc = ngx_hash_add_key(keys, value, u, NGX_HASH_WILDCARD_KEY);
if (rc == NGX_OK) {
- return NGX_CONF_OK;
+ return NGX_OK;
}
if (rc == NGX_DECLINED) {
@@ -531,13 +566,13 @@ ngx_http_add_referer(ngx_conf_t *cf, ngx_hash_keys_arrays_t *keys,
"conflicting parameter \"%V\"", value);
}
- return NGX_CONF_ERROR;
+ return NGX_ERROR;
}
-static char *
+static ngx_int_t
ngx_http_add_regex_referer(ngx_conf_t *cf, ngx_http_referer_conf_t *rlcf,
- ngx_str_t *name, ngx_regex_t *regex)
+ ngx_str_t *name)
{
#if (NGX_PCRE)
ngx_regex_elt_t *re;
@@ -546,26 +581,19 @@ ngx_http_add_regex_referer(ngx_conf_t *cf, ngx_http_referer_conf_t *rlcf,
if (name->len == 1) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty regex in \"%V\"", name);
- return NGX_CONF_ERROR;
+ return NGX_ERROR;
}
if (rlcf->regex == NGX_CONF_UNSET_PTR) {
rlcf->regex = ngx_array_create(cf->pool, 2, sizeof(ngx_regex_elt_t));
if (rlcf->regex == NULL) {
- return NGX_CONF_ERROR;
+ return NGX_ERROR;
}
}
re = ngx_array_push(rlcf->regex);
if (re == NULL) {
- return NGX_CONF_ERROR;
- }
-
- if (regex) {
- re->regex = regex;
- re->name = name->data;
-
- return NGX_CONF_OK;
+ return NGX_ERROR;
}
name->len--;
@@ -581,13 +609,13 @@ ngx_http_add_regex_referer(ngx_conf_t *cf, ngx_http_referer_conf_t *rlcf,
if (ngx_regex_compile(&rc) != NGX_OK) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err);
- return NGX_CONF_ERROR;
+ return NGX_ERROR;
}
re->regex = rc.regex;
re->name = name->data;
- return NGX_CONF_OK;
+ return NGX_OK;
#else
@@ -595,12 +623,42 @@ ngx_http_add_regex_referer(ngx_conf_t *cf, ngx_http_referer_conf_t *rlcf,
"the using of the regex \"%V\" requires PCRE library",
name);
- return NGX_CONF_ERROR;
+ return NGX_ERROR;
#endif
}
+#if (NGX_PCRE)
+
+static ngx_int_t
+ngx_http_add_regex_server_name(ngx_conf_t *cf, ngx_http_referer_conf_t *rlcf,
+ ngx_http_regex_t *regex)
+{
+ ngx_regex_elt_t *re;
+
+ if (rlcf->server_name_regex == NGX_CONF_UNSET_PTR) {
+ rlcf->server_name_regex = ngx_array_create(cf->pool, 2,
+ sizeof(ngx_regex_elt_t));
+ if (rlcf->server_name_regex == NULL) {
+ return NGX_ERROR;
+ }
+ }
+
+ re = ngx_array_push(rlcf->server_name_regex);
+ if (re == NULL) {
+ return NGX_ERROR;
+ }
+
+ re->regex = regex->regex;
+ re->name = regex->name.data;
+
+ return NGX_OK;
+}
+
+#endif
+
+
static int ngx_libc_cdecl
ngx_http_cmp_referer_wildcards(const void *one, const void *two)
{
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_scgi_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_scgi_module.c
index 49cc96d248c..884cb500adf 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_scgi_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_scgi_module.c
@@ -65,6 +65,7 @@ static ngx_conf_bitmask_t ngx_http_scgi_next_upstream_masks[] = {
{ ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
{ ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
{ ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
+ { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 },
{ ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
{ ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING },
{ ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
@@ -261,6 +262,13 @@ static ngx_command_t ngx_http_scgi_commands[] = {
offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_lock_timeout),
NULL },
+ { ngx_string("scgi_cache_revalidate"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_revalidate),
+ NULL },
+
#endif
{ ngx_string("scgi_temp_path"),
@@ -368,7 +376,8 @@ static ngx_str_t ngx_http_scgi_hide_headers[] = {
#if (NGX_HTTP_CACHE)
static ngx_keyval_t ngx_http_scgi_cache_headers[] = {
- { ngx_string("HTTP_IF_MODIFIED_SINCE"), ngx_string("") },
+ { ngx_string("HTTP_IF_MODIFIED_SINCE"),
+ ngx_string("$upstream_cache_last_modified") },
{ ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") },
{ ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("") },
{ ngx_string("HTTP_IF_MATCH"), ngx_string("") },
@@ -393,13 +402,6 @@ ngx_http_scgi_handler(ngx_http_request_t *r)
ngx_http_upstream_t *u;
ngx_http_scgi_loc_conf_t *scf;
- if (r->subrequest_in_memory) {
- ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
- "ngx_http_scgi_module does not support "
- "subrequests in memory");
- return NGX_HTTP_INTERNAL_SERVER_ERROR;
- }
-
if (ngx_http_upstream_create(r) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
@@ -883,7 +885,7 @@ ngx_http_scgi_process_status_line(ngx_http_request_t *r)
return ngx_http_scgi_process_header(r);
}
- if (u->state) {
+ if (u->state && u->state->status == 0) {
u->state->status = status->code;
}
@@ -1011,7 +1013,7 @@ ngx_http_scgi_process_header(ngx_http_request_t *r)
ngx_str_set(&u->headers_in.status_line, "200 OK");
}
- if (u->state) {
+ if (u->state && u->state->status == 0) {
u->state->status = u->headers_in.status_n;
}
@@ -1099,6 +1101,7 @@ ngx_http_scgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
conf->upstream.cache_lock = NGX_CONF_UNSET;
conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
+ conf->upstream.cache_revalidate = NGX_CONF_UNSET;
#endif
conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
@@ -1339,6 +1342,9 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
prev->upstream.cache_lock_timeout, 5000);
+ ngx_conf_merge_value(conf->upstream.cache_revalidate,
+ prev->upstream.cache_revalidate, 0);
+
#endif
ngx_conf_merge_value(conf->upstream.pass_request_headers,
@@ -1500,7 +1506,7 @@ ngx_http_scgi_merge_params(ngx_conf_t *cf, ngx_http_scgi_loc_conf_t *conf,
s->key = h->key;
s->value = h->value;
- s->skip_empty = 0;
+ s->skip_empty = 1;
next:
@@ -1728,7 +1734,7 @@ ngx_http_scgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
sc.source = &value[1];
sc.lengths = &scf->upstream.store_lengths;
sc.values = &scf->upstream.store_values;
- sc.variables = ngx_http_script_variables_count(&value[1]);;
+ sc.variables = ngx_http_script_variables_count(&value[1]);
sc.complete_lengths = 1;
sc.complete_values = 1;
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_ssi_filter_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_ssi_filter_module.c
index eb286cc3475..aeb1376b7bb 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_ssi_filter_module.c
@@ -21,6 +21,7 @@ typedef struct {
ngx_flag_t enable;
ngx_flag_t silent_errors;
ngx_flag_t ignore_recycled_buffers;
+ ngx_flag_t last_modified;
ngx_hash_t types;
@@ -162,6 +163,13 @@ static ngx_command_t ngx_http_ssi_filter_commands[] = {
offsetof(ngx_http_ssi_loc_conf_t, types_keys),
&ngx_http_html_default_types[0] },
+ { ngx_string("ssi_last_modified"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_ssi_loc_conf_t, last_modified),
+ NULL },
+
ngx_null_command
};
@@ -205,6 +213,7 @@ static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
static u_char ngx_http_ssi_string[] = "<!--";
static ngx_str_t ngx_http_ssi_none = ngx_string("(none)");
+static ngx_str_t ngx_http_ssi_timefmt = ngx_string("%A, %d-%b-%Y %H:%M:%S %Z");
static ngx_str_t ngx_http_ssi_null_string = ngx_null_string;
@@ -351,7 +360,7 @@ ngx_http_ssi_header_filter(ngx_http_request_t *r)
ctx->params.nalloc = NGX_HTTP_SSI_PARAMS_N;
ctx->params.pool = r->pool;
- ngx_str_set(&ctx->timefmt, "%A, %d-%b-%Y %H:%M:%S %Z");
+ ctx->timefmt = ngx_http_ssi_timefmt;
ngx_str_set(&ctx->errmsg,
"[an error occurred while processing the directive]");
@@ -359,9 +368,12 @@ ngx_http_ssi_header_filter(ngx_http_request_t *r)
if (r == r->main) {
ngx_http_clear_content_length(r);
- ngx_http_clear_last_modified(r);
ngx_http_clear_accept_ranges(r);
ngx_http_clear_etag(r);
+
+ if (!slcf->last_modified) {
+ ngx_http_clear_last_modified(r);
+ }
}
return ngx_http_next_header_filter(r);
@@ -1971,8 +1983,6 @@ static ngx_int_t
ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
ngx_str_t **params)
{
- u_char *dst, *src;
- size_t len;
ngx_int_t rc, key;
ngx_str_t *uri, *file, *wait, *set, *stub, args;
ngx_buf_t *b;
@@ -2043,18 +2053,6 @@ ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
return rc;
}
- dst = uri->data;
- src = uri->data;
-
- ngx_unescape_uri(&dst, &src, uri->len, NGX_UNESCAPE_URI);
-
- len = (uri->data + uri->len) - src;
- if (len) {
- dst = ngx_movemem(dst, src, len);
- }
-
- uri->len = dst - uri->data;
-
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"ssi include: \"%V\"", uri);
@@ -2723,6 +2721,7 @@ ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r,
{
ngx_http_ssi_ctx_t *ctx;
ngx_time_t *tp;
+ ngx_str_t *timefmt;
struct tm tm;
char buf[NGX_HTTP_SSI_DATE_LEN];
@@ -2734,9 +2733,10 @@ ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r,
ctx = ngx_http_get_module_ctx(r, ngx_http_ssi_filter_module);
- if (ctx == NULL
- || (ctx->timefmt.len == sizeof("%s") - 1
- && ctx->timefmt.data[0] == '%' && ctx->timefmt.data[1] == 's'))
+ timefmt = ctx ? &ctx->timefmt : &ngx_http_ssi_timefmt;
+
+ if (timefmt->len == sizeof("%s") - 1
+ && timefmt->data[0] == '%' && timefmt->data[1] == 's')
{
v->data = ngx_pnalloc(r->pool, NGX_TIME_T_LEN);
if (v->data == NULL) {
@@ -2755,7 +2755,7 @@ ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r,
}
v->len = strftime(buf, NGX_HTTP_SSI_DATE_LEN,
- (char *) ctx->timefmt.data, &tm);
+ (char *) timefmt->data, &tm);
if (v->len == 0) {
return NGX_ERROR;
}
@@ -2878,6 +2878,7 @@ ngx_http_ssi_create_loc_conf(ngx_conf_t *cf)
slcf->enable = NGX_CONF_UNSET;
slcf->silent_errors = NGX_CONF_UNSET;
slcf->ignore_recycled_buffers = NGX_CONF_UNSET;
+ slcf->last_modified = NGX_CONF_UNSET;
slcf->min_file_chunk = NGX_CONF_UNSET_SIZE;
slcf->value_len = NGX_CONF_UNSET_SIZE;
@@ -2896,6 +2897,7 @@ ngx_http_ssi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_value(conf->silent_errors, prev->silent_errors, 0);
ngx_conf_merge_value(conf->ignore_recycled_buffers,
prev->ignore_recycled_buffers, 0);
+ ngx_conf_merge_value(conf->last_modified, prev->last_modified, 0);
ngx_conf_merge_size_value(conf->min_file_chunk, prev->min_file_chunk, 1024);
ngx_conf_merge_size_value(conf->value_len, prev->value_len, 255);
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_ssl_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_ssl_module.c
index a6c803da0dc..206f58d2537 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_ssl_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_ssl_module.c
@@ -17,6 +17,14 @@ typedef ngx_int_t (*ngx_ssl_variable_handler_pt)(ngx_connection_t *c,
#define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5"
#define NGX_DEFAULT_ECDH_CURVE "prime256v1"
+#define NGX_HTTP_NPN_ADVERTISE "\x08http/1.1"
+
+
+#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
+static int ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn,
+ const unsigned char **out, unsigned char *outlen,
+ const unsigned char *in, unsigned int inlen, void *arg);
+#endif
#ifdef TLSEXT_TYPE_next_proto_neg
static int ngx_http_ssl_npn_advertised(ngx_ssl_conn_t *ssl_conn,
@@ -111,6 +119,13 @@ static ngx_command_t ngx_http_ssl_commands[] = {
offsetof(ngx_http_ssl_srv_conf_t, ciphers),
NULL },
+ { ngx_string("ssl_buffer_size"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_size_slot,
+ NGX_HTTP_SRV_CONF_OFFSET,
+ offsetof(ngx_http_ssl_srv_conf_t, buffer_size),
+ NULL },
+
{ ngx_string("ssl_verify_client"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_enum_slot,
@@ -119,7 +134,7 @@ static ngx_command_t ngx_http_ssl_commands[] = {
&ngx_http_ssl_verify },
{ ngx_string("ssl_verify_depth"),
- NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_1MORE,
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_ssl_srv_conf_t, verify_depth),
@@ -153,6 +168,20 @@ static ngx_command_t ngx_http_ssl_commands[] = {
0,
NULL },
+ { ngx_string("ssl_session_tickets"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_SRV_CONF_OFFSET,
+ offsetof(ngx_http_ssl_srv_conf_t, session_tickets),
+ NULL },
+
+ { ngx_string("ssl_session_ticket_key"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_array_slot,
+ NGX_HTTP_SRV_CONF_OFFSET,
+ offsetof(ngx_http_ssl_srv_conf_t, session_ticket_keys),
+ NULL },
+
{ ngx_string("ssl_session_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_sec_slot,
@@ -241,6 +270,9 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = {
{ ngx_string("ssl_session_id"), NULL, ngx_http_ssl_variable,
(uintptr_t) ngx_ssl_get_session_id, NGX_HTTP_VAR_CHANGEABLE, 0 },
+ { ngx_string("ssl_session_reused"), NULL, ngx_http_ssl_variable,
+ (uintptr_t) ngx_ssl_get_session_reused, NGX_HTTP_VAR_CHANGEABLE, 0 },
+
{ ngx_string("ssl_client_cert"), NULL, ngx_http_ssl_variable,
(uintptr_t) ngx_ssl_get_certificate, NGX_HTTP_VAR_CHANGEABLE, 0 },
@@ -267,9 +299,65 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = {
static ngx_str_t ngx_http_ssl_sess_id_ctx = ngx_string("HTTP");
-#ifdef TLSEXT_TYPE_next_proto_neg
+#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
-#define NGX_HTTP_NPN_ADVERTISE "\x08http/1.1"
+static int
+ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out,
+ unsigned char *outlen, const unsigned char *in, unsigned int inlen,
+ void *arg)
+{
+ unsigned int srvlen;
+ unsigned char *srv;
+#if (NGX_DEBUG)
+ unsigned int i;
+#endif
+#if (NGX_HTTP_SPDY)
+ ngx_http_connection_t *hc;
+#endif
+#if (NGX_HTTP_SPDY || NGX_DEBUG)
+ ngx_connection_t *c;
+
+ c = ngx_ssl_get_connection(ssl_conn);
+#endif
+
+#if (NGX_DEBUG)
+ for (i = 0; i < inlen; i += in[i] + 1) {
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
+ "SSL ALPN supported by client: %*s", in[i], &in[i + 1]);
+ }
+#endif
+
+#if (NGX_HTTP_SPDY)
+ hc = c->data;
+
+ if (hc->addr_conf->spdy) {
+ srv = (unsigned char *) NGX_SPDY_NPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE;
+ srvlen = sizeof(NGX_SPDY_NPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE) - 1;
+
+ } else
+#endif
+ {
+ srv = (unsigned char *) NGX_HTTP_NPN_ADVERTISE;
+ srvlen = sizeof(NGX_HTTP_NPN_ADVERTISE) - 1;
+ }
+
+ if (SSL_select_next_proto((unsigned char **) out, outlen, srv, srvlen,
+ in, inlen)
+ != OPENSSL_NPN_NEGOTIATED)
+ {
+ return SSL_TLSEXT_ERR_NOACK;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
+ "SSL ALPN selected: %*s", *outlen, *out);
+
+ return SSL_TLSEXT_ERR_OK;
+}
+
+#endif
+
+
+#ifdef TLSEXT_TYPE_next_proto_neg
static int
ngx_http_ssl_npn_advertised(ngx_ssl_conn_t *ssl_conn,
@@ -417,10 +505,13 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf)
sscf->enable = NGX_CONF_UNSET;
sscf->prefer_server_ciphers = NGX_CONF_UNSET;
+ sscf->buffer_size = NGX_CONF_UNSET_SIZE;
sscf->verify = NGX_CONF_UNSET_UINT;
sscf->verify_depth = NGX_CONF_UNSET_UINT;
sscf->builtin_session_cache = NGX_CONF_UNSET;
sscf->session_timeout = NGX_CONF_UNSET;
+ sscf->session_tickets = NGX_CONF_UNSET;
+ sscf->session_ticket_keys = NGX_CONF_UNSET_PTR;
sscf->stapling = NGX_CONF_UNSET;
sscf->stapling_verify = NGX_CONF_UNSET;
@@ -457,6 +548,9 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
(NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3|NGX_SSL_TLSv1
|NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2));
+ ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size,
+ NGX_SSL_BUFSIZE);
+
ngx_conf_merge_uint_value(conf->verify, prev->verify, 0);
ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1);
@@ -534,6 +628,10 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
#endif
+#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
+ SSL_CTX_set_alpn_select_cb(conf->ssl.ctx, ngx_http_ssl_alpn_select, NULL);
+#endif
+
#ifdef TLSEXT_TYPE_next_proto_neg
SSL_CTX_set_next_protos_advertised_cb(conf->ssl.ctx,
ngx_http_ssl_npn_advertised, NULL);
@@ -561,8 +659,11 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
"SSL_CTX_set_cipher_list(\"%V\") failed",
&conf->ciphers);
+ return NGX_CONF_ERROR;
}
+ conf->ssl.buffer_size = conf->buffer_size;
+
if (conf->verify) {
if (conf->client_certificate.len == 0 && conf->verify != 3) {
@@ -622,6 +723,23 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
return NGX_CONF_ERROR;
}
+ ngx_conf_merge_value(conf->session_tickets, prev->session_tickets, 1);
+
+#ifdef SSL_OP_NO_TICKET
+ if (!conf->session_tickets) {
+ SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_NO_TICKET);
+ }
+#endif
+
+ ngx_conf_merge_ptr_value(conf->session_ticket_keys,
+ prev->session_ticket_keys, NULL);
+
+ if (ngx_ssl_session_ticket_keys(cf, &conf->ssl, conf->session_ticket_keys)
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
+
if (conf->stapling) {
if (ngx_ssl_stapling(cf, &conf->ssl, &conf->stapling_file,
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_ssl_module.h b/usr.sbin/nginx/src/http/modules/ngx_http_ssl_module.h
index c4c576ef63b..ec2c62f6fb5 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_ssl_module.h
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_ssl_module.h
@@ -26,6 +26,8 @@ typedef struct {
ngx_uint_t verify;
ngx_uint_t verify_depth;
+ size_t buffer_size;
+
ssize_t builtin_session_cache;
time_t session_timeout;
@@ -42,6 +44,9 @@ typedef struct {
ngx_shm_zone_t *shm_zone;
+ ngx_flag_t session_tickets;
+ ngx_array_t *session_ticket_keys;
+
ngx_flag_t stapling;
ngx_flag_t stapling_verify;
ngx_str_t stapling_file;
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_stub_status_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_stub_status_module.c
index 83a35cda814..b5ecd6d9e2f 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_stub_status_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_stub_status_module.c
@@ -98,7 +98,9 @@ static ngx_int_t ngx_http_status_handler(ngx_http_request_t *r)
return rc;
}
+ r->headers_out.content_type_len = sizeof("text/plain") - 1;
ngx_str_set(&r->headers_out.content_type, "text/plain");
+ r->headers_out.content_type_lowcase = NULL;
if (r->method == NGX_HTTP_HEAD) {
r->headers_out.status = NGX_HTTP_OK;
@@ -145,6 +147,7 @@ static ngx_int_t ngx_http_status_handler(ngx_http_request_t *r)
r->headers_out.content_length_n = b->last - b->pos;
b->last_buf = (r == r->main) ? 1 : 0;
+ b->last_in_chain = 1;
rc = ngx_http_send_header(r);
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_sub_filter_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_sub_filter_module.c
index 6ba57dfffc0..a4d666bed2b 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_sub_filter_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_sub_filter_module.c
@@ -17,6 +17,7 @@ typedef struct {
ngx_hash_t types;
ngx_flag_t once;
+ ngx_flag_t last_modified;
ngx_array_t *types_keys;
} ngx_http_sub_loc_conf_t;
@@ -89,6 +90,13 @@ static ngx_command_t ngx_http_sub_filter_commands[] = {
offsetof(ngx_http_sub_loc_conf_t, once),
NULL },
+ { ngx_string("sub_filter_last_modified"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_sub_loc_conf_t, last_modified),
+ NULL },
+
ngx_null_command
};
@@ -167,8 +175,11 @@ ngx_http_sub_header_filter(ngx_http_request_t *r)
if (r == r->main) {
ngx_http_clear_content_length(r);
- ngx_http_clear_last_modified(r);
ngx_http_clear_etag(r);
+
+ if (!slcf->last_modified) {
+ ngx_http_clear_last_modified(r);
+ }
}
return ngx_http_next_header_filter(r);
@@ -250,66 +261,43 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
return rc;
}
- if (ctx->copy_start != ctx->copy_end) {
+ if (ctx->saved.len) {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"saved: \"%V\"", &ctx->saved);
- if (ctx->saved.len) {
+ cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
+ if (cl == NULL) {
+ return NGX_ERROR;
+ }
- if (ctx->free) {
- cl = ctx->free;
- ctx->free = ctx->free->next;
- b = cl->buf;
- ngx_memzero(b, sizeof(ngx_buf_t));
+ b = cl->buf;
- } else {
- b = ngx_calloc_buf(r->pool);
- if (b == NULL) {
- return NGX_ERROR;
- }
+ ngx_memzero(b, sizeof(ngx_buf_t));
- cl = ngx_alloc_chain_link(r->pool);
- if (cl == NULL) {
- return NGX_ERROR;
- }
+ b->pos = ngx_pnalloc(r->pool, ctx->saved.len);
+ if (b->pos == NULL) {
+ return NGX_ERROR;
+ }
- cl->buf = b;
- }
+ ngx_memcpy(b->pos, ctx->saved.data, ctx->saved.len);
+ b->last = b->pos + ctx->saved.len;
+ b->memory = 1;
- b->pos = ngx_pnalloc(r->pool, ctx->saved.len);
- if (b->pos == NULL) {
- return NGX_ERROR;
- }
+ *ctx->last_out = cl;
+ ctx->last_out = &cl->next;
- ngx_memcpy(b->pos, ctx->saved.data, ctx->saved.len);
- b->last = b->pos + ctx->saved.len;
- b->memory = 1;
+ ctx->saved.len = 0;
+ }
- *ctx->last_out = cl;
- ctx->last_out = &cl->next;
+ if (ctx->copy_start != ctx->copy_end) {
- ctx->saved.len = 0;
+ cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
+ if (cl == NULL) {
+ return NGX_ERROR;
}
- if (ctx->free) {
- cl = ctx->free;
- ctx->free = ctx->free->next;
- b = cl->buf;
-
- } else {
- b = ngx_alloc_buf(r->pool);
- if (b == NULL) {
- return NGX_ERROR;
- }
-
- cl = ngx_alloc_chain_link(r->pool);
- if (cl == NULL) {
- return NGX_ERROR;
- }
-
- cl->buf = b;
- }
+ b = cl->buf;
ngx_memcpy(b, ctx->buf, sizeof(ngx_buf_t));
@@ -324,7 +312,6 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
b->file_pos += b->pos - ctx->buf->pos;
}
- cl->next = NULL;
*ctx->last_out = cl;
ctx->last_out = &cl->next;
}
@@ -338,6 +325,11 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
ctx->copy_end = NULL;
}
+ if (ctx->looked.len > (size_t) (ctx->pos - ctx->buf->pos)) {
+ ctx->saved.len = ctx->looked.len - (ctx->pos - ctx->buf->pos);
+ ngx_memcpy(ctx->saved.data, ctx->looked.data, ctx->saved.len);
+ }
+
if (rc == NGX_AGAIN) {
continue;
}
@@ -345,16 +337,15 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
/* rc == NGX_OK */
- b = ngx_calloc_buf(r->pool);
- if (b == NULL) {
- return NGX_ERROR;
- }
-
- cl = ngx_alloc_chain_link(r->pool);
+ cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
if (cl == NULL) {
return NGX_ERROR;
}
+ b = cl->buf;
+
+ ngx_memzero(b, sizeof(ngx_buf_t));
+
slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module);
if (ctx->sub.data == NULL) {
@@ -375,8 +366,6 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
b->sync = 1;
}
- cl->buf = b;
- cl->next = NULL;
*ctx->last_out = cl;
ctx->last_out = &cl->next;
@@ -385,36 +374,47 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
continue;
}
- if (ctx->buf->last_buf || ngx_buf_in_memory(ctx->buf)) {
+ if (ctx->buf->last_buf && ctx->looked.len) {
+ cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
+ if (cl == NULL) {
+ return NGX_ERROR;
+ }
+
+ b = cl->buf;
+
+ ngx_memzero(b, sizeof(ngx_buf_t));
+
+ b->pos = ctx->looked.data;
+ b->last = b->pos + ctx->looked.len;
+ b->memory = 1;
+
+ *ctx->last_out = cl;
+ ctx->last_out = &cl->next;
+
+ ctx->looked.len = 0;
+ }
+
+ if (ctx->buf->last_buf || ctx->buf->flush
+ || ngx_buf_in_memory(ctx->buf))
+ {
if (b == NULL) {
- if (ctx->free) {
- cl = ctx->free;
- ctx->free = ctx->free->next;
- b = cl->buf;
- ngx_memzero(b, sizeof(ngx_buf_t));
-
- } else {
- b = ngx_calloc_buf(r->pool);
- if (b == NULL) {
- return NGX_ERROR;
- }
-
- cl = ngx_alloc_chain_link(r->pool);
- if (cl == NULL) {
- return NGX_ERROR;
- }
-
- cl->buf = b;
+ cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
+ if (cl == NULL) {
+ return NGX_ERROR;
}
+ b = cl->buf;
+
+ ngx_memzero(b, sizeof(ngx_buf_t));
+
b->sync = 1;
- cl->next = NULL;
*ctx->last_out = cl;
ctx->last_out = &cl->next;
}
b->last_buf = ctx->buf->last_buf;
+ b->flush = ctx->buf->flush;
b->shadow = ctx->buf;
b->recycled = ctx->buf->recycled;
@@ -507,7 +507,7 @@ static ngx_int_t
ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx)
{
u_char *p, *last, *copy_end, ch, match;
- size_t looked;
+ size_t looked, i;
ngx_http_sub_state_e state;
if (ctx->once) {
@@ -578,13 +578,11 @@ ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx)
looked++;
if (looked == ctx->match.len) {
- if ((size_t) (p - ctx->pos) < looked) {
- ctx->saved.len = 0;
- }
ctx->state = sub_start_state;
ctx->pos = p + 1;
ctx->looked.len = 0;
+ ctx->saved.len = 0;
ctx->copy_end = copy_end;
if (ctx->copy_start == NULL && copy_end) {
@@ -594,18 +592,53 @@ ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx)
return NGX_OK;
}
- } else if (ch == ctx->match.data[0]) {
- copy_end = p;
- ctx->looked.data[0] = *p;
- looked = 1;
-
} else {
- copy_end = p;
- looked = 0;
- state = sub_start_state;
+ /*
+ * check if there is another partial match in previously
+ * matched substring to catch cases like "aab" in "aaab"
+ */
+
+ ctx->looked.data[looked] = *p;
+ looked++;
+
+ for (i = 1; i < looked; i++) {
+ if (ngx_strncasecmp(ctx->looked.data + i,
+ ctx->match.data, looked - i)
+ == 0)
+ {
+ break;
+ }
+ }
+
+ if (i < looked) {
+ if (ctx->saved.len > i) {
+ ctx->saved.len = i;
+ }
+
+ if ((size_t) (p + 1 - ctx->buf->pos) >= looked - i) {
+ copy_end = p + 1 - (looked - i);
+ }
+
+ ngx_memmove(ctx->looked.data, ctx->looked.data + i, looked - i);
+ looked = looked - i;
+
+ } else {
+ copy_end = p;
+ looked = 0;
+ state = sub_start_state;
+ }
+
+ if (ctx->saved.len) {
+ p++;
+ goto out;
+ }
}
}
+ ctx->saved.len = 0;
+
+out:
+
ctx->state = state;
ctx->pos = p;
ctx->looked.len = looked;
@@ -666,14 +699,12 @@ ngx_http_sub_create_conf(ngx_conf_t *cf)
* set by ngx_pcalloc():
*
* conf->match = { 0, NULL };
- * conf->sub = { 0, NULL };
- * conf->sub_lengths = NULL;
- * conf->sub_values = NULL;
* conf->types = { NULL };
* conf->types_keys = NULL;
*/
slcf->once = NGX_CONF_UNSET;
+ slcf->last_modified = NGX_CONF_UNSET;
return slcf;
}
@@ -687,6 +718,7 @@ ngx_http_sub_merge_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_value(conf->once, prev->once, 1);
ngx_conf_merge_str_value(conf->match, prev->match, "");
+ ngx_conf_merge_value(conf->last_modified, prev->last_modified, 0);
if (conf->value.value.data == NULL) {
conf->value = prev->value;
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_upstream_ip_hash_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_upstream_ip_hash_module.c
index 29c74fd54d0..041883fec82 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_upstream_ip_hash_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_upstream_ip_hash_module.c
@@ -174,7 +174,7 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
for ( ;; ) {
- for (i = 0; i < iphp->addrlen; i++) {
+ for (i = 0; i < (ngx_uint_t) iphp->addrlen; i++) {
hash = (hash * 113 + iphp->addr[i]) % 6271;
}
@@ -197,33 +197,39 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
n = p / (8 * sizeof(uintptr_t));
m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));
- if (!(iphp->rrp.tried[n] & m)) {
+ if (iphp->rrp.tried[n] & m) {
+ goto next;
+ }
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
- "get ip hash peer, hash: %ui %04XA", p, m);
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
+ "get ip hash peer, hash: %ui %04XA", p, m);
- peer = &iphp->rrp.peers->peer[p];
+ peer = &iphp->rrp.peers->peer[p];
- /* ngx_lock_mutex(iphp->rrp.peers->mutex); */
+ /* ngx_lock_mutex(iphp->rrp.peers->mutex); */
- if (!peer->down) {
+ if (peer->down) {
+ goto next_try;
+ }
- if (peer->max_fails == 0 || peer->fails < peer->max_fails) {
- break;
- }
+ if (peer->max_fails
+ && peer->fails >= peer->max_fails
+ && now - peer->checked <= peer->fail_timeout)
+ {
+ goto next_try;
+ }
- if (now - peer->checked > peer->fail_timeout) {
- peer->checked = now;
- break;
- }
- }
+ break;
- iphp->rrp.tried[n] |= m;
+ next_try:
- /* ngx_unlock_mutex(iphp->rrp.peers->mutex); */
+ iphp->rrp.tried[n] |= m;
- pc->tries--;
- }
+ /* ngx_unlock_mutex(iphp->rrp.peers->mutex); */
+
+ pc->tries--;
+
+ next:
if (++iphp->tries >= 20) {
return iphp->get_rr_peer(pc, &iphp->rrp);
@@ -236,6 +242,10 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
pc->socklen = peer->socklen;
pc->name = &peer->name;
+ if (now - peer->checked > peer->fail_timeout) {
+ peer->checked = now;
+ }
+
/* ngx_unlock_mutex(iphp->rrp.peers->mutex); */
iphp->rrp.tried[n] |= m;
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_upstream_keepalive_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_upstream_keepalive_module.c
index eed117404f4..d07ed9edaf2 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_upstream_keepalive_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_upstream_keepalive_module.c
@@ -81,7 +81,7 @@ static ngx_command_t ngx_http_upstream_keepalive_commands[] = {
{ ngx_string("keepalive"),
NGX_HTTP_UPS_CONF|NGX_CONF_TAKE12,
ngx_http_upstream_keepalive,
- 0,
+ NGX_HTTP_SRV_CONF_OFFSET,
0,
NULL },
@@ -481,7 +481,7 @@ static char *
ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_upstream_srv_conf_t *uscf;
- ngx_http_upstream_keepalive_srv_conf_t *kcf;
+ ngx_http_upstream_keepalive_srv_conf_t *kcf = conf;
ngx_int_t n;
ngx_str_t *value;
@@ -489,9 +489,6 @@ ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);
- kcf = ngx_http_conf_upstream_srv_conf(uscf,
- ngx_http_upstream_keepalive_module);
-
if (kcf->original_init_upstream) {
return "is duplicate";
}
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_uwsgi_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_uwsgi_module.c
index 623ee495771..17dfc3b3ac7 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_uwsgi_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_uwsgi_module.c
@@ -34,6 +34,12 @@ typedef struct {
ngx_uint_t modifier1;
ngx_uint_t modifier2;
+
+#if (NGX_HTTP_SSL)
+ ngx_uint_t ssl;
+ ngx_uint_t ssl_protocols;
+ ngx_str_t ssl_ciphers;
+#endif
} ngx_http_uwsgi_loc_conf_t;
@@ -66,6 +72,11 @@ static char *ngx_http_uwsgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
#endif
+#if (NGX_HTTP_SSL)
+static ngx_int_t ngx_http_uwsgi_set_ssl(ngx_conf_t *cf,
+ ngx_http_uwsgi_loc_conf_t *uwcf);
+#endif
+
static ngx_conf_num_bounds_t ngx_http_uwsgi_modifier_bounds = {
ngx_conf_check_num_bounds, 0, 255
@@ -78,6 +89,7 @@ static ngx_conf_bitmask_t ngx_http_uwsgi_next_upstream_masks[] = {
{ ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
{ ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
{ ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
+ { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 },
{ ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
{ ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING },
{ ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
@@ -85,6 +97,20 @@ static ngx_conf_bitmask_t ngx_http_uwsgi_next_upstream_masks[] = {
};
+#if (NGX_HTTP_SSL)
+
+static ngx_conf_bitmask_t ngx_http_uwsgi_ssl_protocols[] = {
+ { ngx_string("SSLv2"), NGX_SSL_SSLv2 },
+ { ngx_string("SSLv3"), NGX_SSL_SSLv3 },
+ { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
+ { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 },
+ { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 },
+ { ngx_null_string, 0 }
+};
+
+#endif
+
+
ngx_module_t ngx_http_uwsgi_module;
@@ -288,6 +314,13 @@ static ngx_command_t ngx_http_uwsgi_commands[] = {
offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_lock_timeout),
NULL },
+ { ngx_string("uwsgi_cache_revalidate"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_revalidate),
+ NULL },
+
#endif
{ ngx_string("uwsgi_temp_path"),
@@ -353,6 +386,31 @@ static ngx_command_t ngx_http_uwsgi_commands[] = {
offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ignore_headers),
&ngx_http_upstream_ignore_headers_masks },
+#if (NGX_HTTP_SSL)
+
+ { ngx_string("uwsgi_ssl_session_reuse"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ssl_session_reuse),
+ NULL },
+
+ { ngx_string("uwsgi_ssl_protocols"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+ ngx_conf_set_bitmask_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_uwsgi_loc_conf_t, ssl_protocols),
+ &ngx_http_uwsgi_ssl_protocols },
+
+ { ngx_string("uwsgi_ssl_ciphers"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_uwsgi_loc_conf_t, ssl_ciphers),
+ NULL },
+
+#endif
+
ngx_null_command
};
@@ -401,7 +459,8 @@ static ngx_str_t ngx_http_uwsgi_hide_headers[] = {
#if (NGX_HTTP_CACHE)
static ngx_keyval_t ngx_http_uwsgi_cache_headers[] = {
- { ngx_string("HTTP_IF_MODIFIED_SINCE"), ngx_string("") },
+ { ngx_string("HTTP_IF_MODIFIED_SINCE"),
+ ngx_string("$upstream_cache_last_modified") },
{ ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") },
{ ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("") },
{ ngx_string("HTTP_IF_MATCH"), ngx_string("") },
@@ -426,13 +485,6 @@ ngx_http_uwsgi_handler(ngx_http_request_t *r)
ngx_http_upstream_t *u;
ngx_http_uwsgi_loc_conf_t *uwcf;
- if (r->subrequest_in_memory) {
- ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
- "ngx_http_uwsgi_module does not support "
- "subrequests in memory");
- return NGX_HTTP_INTERNAL_SERVER_ERROR;
- }
-
if (ngx_http_upstream_create(r) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
@@ -446,15 +498,29 @@ ngx_http_uwsgi_handler(ngx_http_request_t *r)
uwcf = ngx_http_get_module_loc_conf(r, ngx_http_uwsgi_module);
- if (uwcf->uwsgi_lengths) {
+ u = r->upstream;
+
+ if (uwcf->uwsgi_lengths == NULL) {
+
+#if (NGX_HTTP_SSL)
+ u->ssl = (uwcf->upstream.ssl != NULL);
+
+ if (u->ssl) {
+ ngx_str_set(&u->schema, "suwsgi://");
+
+ } else {
+ ngx_str_set(&u->schema, "uwsgi://");
+ }
+#else
+ ngx_str_set(&u->schema, "uwsgi://");
+#endif
+
+ } else {
if (ngx_http_uwsgi_eval(r, uwcf) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
}
- u = r->upstream;
-
- ngx_str_set(&u->schema, "uwsgi://");
u->output.tag = (ngx_buf_tag_t) &ngx_http_uwsgi_module;
u->conf = &uwcf->upstream;
@@ -492,6 +558,7 @@ ngx_http_uwsgi_handler(ngx_http_request_t *r)
static ngx_int_t
ngx_http_uwsgi_eval(ngx_http_request_t *r, ngx_http_uwsgi_loc_conf_t * uwcf)
{
+ size_t add;
ngx_url_t url;
ngx_http_upstream_t *u;
@@ -504,6 +571,41 @@ ngx_http_uwsgi_eval(ngx_http_request_t *r, ngx_http_uwsgi_loc_conf_t * uwcf)
return NGX_ERROR;
}
+ if (url.url.len > 8
+ && ngx_strncasecmp(url.url.data, (u_char *) "uwsgi://", 8) == 0)
+ {
+ add = 8;
+
+ } else if (url.url.len > 9
+ && ngx_strncasecmp(url.url.data, (u_char *) "suwsgi://", 9) == 0)
+ {
+
+#if (NGX_HTTP_SSL)
+ add = 9;
+ r->upstream->ssl = 1;
+#else
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "suwsgi protocol requires SSL support");
+ return NGX_ERROR;
+#endif
+
+ } else {
+ add = 0;
+ }
+
+ u = r->upstream;
+
+ if (add) {
+ u->schema.len = add;
+ u->schema.data = url.url.data;
+
+ url.url.data += add;
+ url.url.len -= add;
+
+ } else {
+ ngx_str_set(&u->schema, "uwsgi://");
+ }
+
url.no_resolve = 1;
if (ngx_parse_url(r->pool, &url) != NGX_OK) {
@@ -515,8 +617,6 @@ ngx_http_uwsgi_eval(ngx_http_request_t *r, ngx_http_uwsgi_loc_conf_t * uwcf)
return NGX_ERROR;
}
- u = r->upstream;
-
u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
if (u->resolved == NULL) {
return NGX_ERROR;
@@ -917,7 +1017,7 @@ ngx_http_uwsgi_process_status_line(ngx_http_request_t *r)
return ngx_http_uwsgi_process_header(r);
}
- if (u->state) {
+ if (u->state && u->state->status == 0) {
u->state->status = status->code;
}
@@ -1045,7 +1145,7 @@ ngx_http_uwsgi_process_header(ngx_http_request_t *r)
ngx_str_set(&u->headers_in.status_line, "200 OK");
}
- if (u->state) {
+ if (u->state && u->state->status == 0) {
u->state->status = u->headers_in.status_n;
}
@@ -1136,12 +1236,16 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
conf->upstream.cache_lock = NGX_CONF_UNSET;
conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
+ conf->upstream.cache_revalidate = NGX_CONF_UNSET;
#endif
conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
conf->upstream.intercept_errors = NGX_CONF_UNSET;
+#if (NGX_HTTP_SSL)
+ conf->upstream.ssl_session_reuse = NGX_CONF_UNSET;
+#endif
/* "uwsgi_cyclic_temp_file" is disabled */
conf->upstream.cyclic_temp_file = 0;
@@ -1376,6 +1480,9 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
prev->upstream.cache_lock_timeout, 5000);
+ ngx_conf_merge_value(conf->upstream.cache_revalidate,
+ prev->upstream.cache_revalidate, 0);
+
#endif
ngx_conf_merge_value(conf->upstream.pass_request_headers,
@@ -1386,6 +1493,27 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_value(conf->upstream.intercept_errors,
prev->upstream.intercept_errors, 0);
+#if (NGX_HTTP_SSL)
+ ngx_conf_merge_value(conf->upstream.ssl_session_reuse,
+ prev->upstream.ssl_session_reuse, 1);
+
+ ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols,
+ (NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3
+ |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1
+ |NGX_SSL_TLSv1_2));
+
+ ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers,
+ "DEFAULT");
+
+ if (conf->ssl && ngx_http_uwsgi_set_ssl(cf, conf) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (conf->upstream.ssl == NULL) {
+ conf->upstream.ssl = prev->upstream.ssl;
+ }
+#endif
+
ngx_conf_merge_str_value(conf->uwsgi_string, prev->uwsgi_string, "");
hash.max_size = 512;
@@ -1542,7 +1670,7 @@ ngx_http_uwsgi_merge_params(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *conf,
s->key = h->key;
s->value = h->value;
- s->skip_empty = 0;
+ s->skip_empty = 1;
next:
@@ -1664,6 +1792,7 @@ ngx_http_uwsgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_uwsgi_loc_conf_t *uwcf = conf;
+ size_t add;
ngx_url_t u;
ngx_str_t *value, *url;
ngx_uint_t n;
@@ -1699,12 +1828,35 @@ ngx_http_uwsgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return NGX_CONF_ERROR;
}
+#if (NGX_HTTP_SSL)
+ uwcf->ssl = 1;
+#endif
+
return NGX_CONF_OK;
}
+ if (ngx_strncasecmp(url->data, (u_char *) "uwsgi://", 8) == 0) {
+ add = 8;
+
+ } else if (ngx_strncasecmp(url->data, (u_char *) "suwsgi://", 9) == 0) {
+
+#if (NGX_HTTP_SSL)
+ add = 9;
+ uwcf->ssl = 1;
+#else
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "suwsgi protocol requires SSL support");
+ return NGX_CONF_ERROR;
+#endif
+
+ } else {
+ add = 0;
+ }
+
ngx_memzero(&u, sizeof(ngx_url_t));
- u.url = value[1];
+ u.url.len = url->len - add;
+ u.url.data = url->data + add;
u.no_resolve = 1;
uwcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
@@ -1764,7 +1916,7 @@ ngx_http_uwsgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
sc.source = &value[1];
sc.lengths = &uwcf->upstream.store_lengths;
sc.values = &uwcf->upstream.store_values;
- sc.variables = ngx_http_script_variables_count(&value[1]);;
+ sc.variables = ngx_http_script_variables_count(&value[1]);
sc.complete_lengths = 1;
sc.complete_values = 1;
@@ -1838,3 +1990,47 @@ ngx_http_uwsgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}
#endif
+
+
+#if (NGX_HTTP_SSL)
+
+static ngx_int_t
+ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf)
+{
+ ngx_pool_cleanup_t *cln;
+
+ uwcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
+ if (uwcf->upstream.ssl == NULL) {
+ return NGX_ERROR;
+ }
+
+ uwcf->upstream.ssl->log = cf->log;
+
+ if (ngx_ssl_create(uwcf->upstream.ssl, uwcf->ssl_protocols, NULL)
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+
+ if (SSL_CTX_set_cipher_list(uwcf->upstream.ssl->ctx,
+ (const char *) uwcf->ssl_ciphers.data)
+ == 0)
+ {
+ ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
+ "SSL_CTX_set_cipher_list(\"%V\") failed",
+ &uwcf->ssl_ciphers);
+ return NGX_ERROR;
+ }
+
+ cln = ngx_pool_cleanup_add(cf->pool, 0);
+ if (cln == NULL) {
+ return NGX_ERROR;
+ }
+
+ cln->handler = ngx_ssl_cleanup_ctx;
+ cln->data = uwcf->upstream.ssl;
+
+ return NGX_OK;
+}
+
+#endif
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_xslt_filter_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_xslt_filter_module.c
index a6ae1ce02b8..9e85693bcc4 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_xslt_filter_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_xslt_filter_module.c
@@ -58,6 +58,7 @@ typedef struct {
ngx_hash_t types;
ngx_array_t *types_keys;
ngx_array_t *params; /* ngx_http_xslt_param_t */
+ ngx_flag_t last_modified;
} ngx_http_xslt_filter_loc_conf_t;
@@ -103,6 +104,7 @@ static void *ngx_http_xslt_filter_create_main_conf(ngx_conf_t *cf);
static void *ngx_http_xslt_filter_create_conf(ngx_conf_t *cf);
static char *ngx_http_xslt_filter_merge_conf(ngx_conf_t *cf, void *parent,
void *child);
+static ngx_int_t ngx_http_xslt_filter_preconfiguration(ngx_conf_t *cf);
static ngx_int_t ngx_http_xslt_filter_init(ngx_conf_t *cf);
static void ngx_http_xslt_filter_exit(ngx_cycle_t *cycle);
@@ -150,12 +152,19 @@ static ngx_command_t ngx_http_xslt_filter_commands[] = {
offsetof(ngx_http_xslt_filter_loc_conf_t, types_keys),
&ngx_http_xslt_default_types[0] },
+ { ngx_string("xslt_last_modified"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_xslt_filter_loc_conf_t, last_modified),
+ NULL },
+
ngx_null_command
};
static ngx_http_module_t ngx_http_xslt_filter_module_ctx = {
- NULL, /* preconfiguration */
+ ngx_http_xslt_filter_preconfiguration, /* preconfiguration */
ngx_http_xslt_filter_init, /* postconfiguration */
ngx_http_xslt_filter_create_main_conf, /* create main configuration */
@@ -300,9 +309,10 @@ static ngx_int_t
ngx_http_xslt_send(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx,
ngx_buf_t *b)
{
- ngx_int_t rc;
- ngx_chain_t out;
- ngx_pool_cleanup_t *cln;
+ ngx_int_t rc;
+ ngx_chain_t out;
+ ngx_pool_cleanup_t *cln;
+ ngx_http_xslt_filter_loc_conf_t *conf;
ctx->done = 1;
@@ -327,8 +337,13 @@ ngx_http_xslt_send(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx,
r->headers_out.content_length = NULL;
}
- ngx_http_clear_last_modified(r);
ngx_http_clear_etag(r);
+
+ conf = ngx_http_get_module_loc_conf(r, ngx_http_xslt_filter_module);
+
+ if (!conf->last_modified) {
+ ngx_http_clear_last_modified(r);
+ }
}
rc = ngx_http_next_header_filter(r);
@@ -1058,6 +1073,8 @@ ngx_http_xslt_filter_create_conf(ngx_conf_t *cf)
* conf->params = NULL;
*/
+ conf->last_modified = NGX_CONF_UNSET;
+
return conf;
}
@@ -1088,12 +1105,14 @@ ngx_http_xslt_filter_merge_conf(ngx_conf_t *cf, void *parent, void *child)
return NGX_CONF_ERROR;
}
+ ngx_conf_merge_value(conf->last_modified, prev->last_modified, 0);
+
return NGX_CONF_OK;
}
static ngx_int_t
-ngx_http_xslt_filter_init(ngx_conf_t *cf)
+ngx_http_xslt_filter_preconfiguration(ngx_conf_t *cf)
{
xmlInitParser();
@@ -1101,6 +1120,13 @@ ngx_http_xslt_filter_init(ngx_conf_t *cf)
exsltRegisterAll();
#endif
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_xslt_filter_init(ngx_conf_t *cf)
+{
ngx_http_next_header_filter = ngx_http_top_header_filter;
ngx_http_top_header_filter = ngx_http_xslt_header_filter;
diff --git a/usr.sbin/nginx/src/http/modules/perl/nginx.xs b/usr.sbin/nginx/src/http/modules/perl/nginx.xs
index 77fb653739a..71f17a8bb45 100644
--- a/usr.sbin/nginx/src/http/modules/perl/nginx.xs
+++ b/usr.sbin/nginx/src/http/modules/perl/nginx.xs
@@ -261,13 +261,12 @@ header_in(r, key)
sep = ';';
goto multi;
}
-
- #if (NGX_HTTP_X_FORWARDED_FOR)
+#if (NGX_HTTP_X_FORWARDED_FOR)
if (hh->offset == offsetof(ngx_http_headers_in_t, x_forwarded_for)) {
sep = ',';
goto multi;
}
- #endif
+#endif
if (hh->offset) {
@@ -898,8 +897,7 @@ variable(r, name, value = NULL)
var.len = len;
var.data = lowcase;
-
- #if (NGX_DEBUG)
+#if (NGX_DEBUG)
if (value) {
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -908,8 +906,7 @@ variable(r, name, value = NULL)
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"perl variable: \"%V\"", &var);
}
-
- #endif
+#endif
vv = ngx_http_get_variable(r, &var, hash);
if (vv == NULL) {
diff --git a/usr.sbin/nginx/src/http/modules/perl/ngx_http_perl_module.c b/usr.sbin/nginx/src/http/modules/perl/ngx_http_perl_module.c
index 90e32e80efa..bf4d1fe9ad7 100644
--- a/usr.sbin/nginx/src/http/modules/perl/ngx_http_perl_module.c
+++ b/usr.sbin/nginx/src/http/modules/perl/ngx_http_perl_module.c
@@ -421,7 +421,7 @@ ngx_http_perl_ssi(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ssi_ctx,
return NGX_ERROR;
}
- asv[0] = (SV *) i;
+ asv[0] = (SV *) (uintptr_t) i;
for (i = 0; args[i]; i++) {
asv[i + 1] = newSVpvn((char *) args[i]->data, args[i]->len);
@@ -692,7 +692,7 @@ ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, HV *nginx, SV *sub,
if (args) {
EXTEND(sp, (intptr_t) args[0]);
- for (i = 1; i <= (ngx_uint_t) args[0]; i++) {
+ for (i = 1; i <= (uintptr_t) args[0]; i++) {
PUSHs(sv_2mortal(args[i]));
}
}
diff --git a/usr.sbin/nginx/src/http/ngx_http.c b/usr.sbin/nginx/src/http/ngx_http.c
index 987ae54df66..ce5adb7374a 100644
--- a/usr.sbin/nginx/src/http/ngx_http.c
+++ b/usr.sbin/nginx/src/http/ngx_http.c
@@ -949,7 +949,8 @@ ngx_http_cmp_locations(const ngx_queue_t *one, const ngx_queue_t *two)
#endif
- rc = ngx_strcmp(first->name.data, second->name.data);
+ rc = ngx_filename_cmp(first->name.data, second->name.data,
+ ngx_min(first->name.len, second->name.len) + 1);
if (rc == 0 && !first->exact_match && second->exact_match) {
/* an exact match must be before the same inclusive one */
@@ -975,8 +976,10 @@ ngx_http_join_exact_locations(ngx_conf_t *cf, ngx_queue_t *locations)
lq = (ngx_http_location_queue_t *) q;
lx = (ngx_http_location_queue_t *) x;
- if (ngx_strcmp(lq->name->data, lx->name->data) == 0) {
-
+ if (lq->name->len == lx->name->len
+ && ngx_filename_cmp(lq->name->data, lx->name->data, lx->name->len)
+ == 0)
+ {
if ((lq->exact && lx->exact) || (lq->inclusive && lx->inclusive)) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"duplicate location \"%V\" in %s:%ui",
@@ -1028,7 +1031,7 @@ ngx_http_create_locations_list(ngx_queue_t *locations, ngx_queue_t *q)
lx = (ngx_http_location_queue_t *) x;
if (len > lx->name->len
- || (ngx_strncmp(name, lx->name->data, len) != 0))
+ || ngx_filename_cmp(name, lx->name->data, len) != 0)
{
break;
}
@@ -1346,11 +1349,13 @@ ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
}
}
-#if (NGX_HTTP_SPDY && NGX_HTTP_SSL && !defined TLSEXT_TYPE_next_proto_neg)
+#if (NGX_HTTP_SPDY && NGX_HTTP_SSL \
+ && !defined TLSEXT_TYPE_application_layer_protocol_negotiation \
+ && !defined TLSEXT_TYPE_next_proto_neg)
if (lsopt->spdy && lsopt->ssl) {
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
- "nginx was built without OpenSSL NPN support, "
- "SPDY is not enabled for %s", lsopt->addr);
+ "nginx was built without OpenSSL ALPN or NPN "
+ "support, SPDY is not enabled for %s", lsopt->addr);
}
#endif
@@ -1808,6 +1813,10 @@ ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr)
ls->setfib = addr->opt.setfib;
#endif
+#if (NGX_HAVE_TCP_FASTOPEN)
+ ls->fastopen = addr->opt.fastopen;
+#endif
+
return ls;
}
@@ -1840,6 +1849,7 @@ ngx_http_add_addrs(ngx_conf_t *cf, ngx_http_port_t *hport,
#if (NGX_HTTP_SPDY)
addrs[i].conf.spdy = addr[i].opt.spdy;
#endif
+ addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol;
if (addr[i].hash.buckets == NULL
&& (addr[i].wc_head == NULL
diff --git a/usr.sbin/nginx/src/http/ngx_http_cache.h b/usr.sbin/nginx/src/http/ngx_http_cache.h
index 2a2d7229153..193a35322b5 100644
--- a/usr.sbin/nginx/src/http/ngx_http_cache.h
+++ b/usr.sbin/nginx/src/http/ngx_http_cache.h
@@ -19,8 +19,9 @@
#define NGX_HTTP_CACHE_EXPIRED 3
#define NGX_HTTP_CACHE_STALE 4
#define NGX_HTTP_CACHE_UPDATING 5
-#define NGX_HTTP_CACHE_HIT 6
-#define NGX_HTTP_CACHE_SCARCE 7
+#define NGX_HTTP_CACHE_REVALIDATED 6
+#define NGX_HTTP_CACHE_HIT 7
+#define NGX_HTTP_CACHE_SCARCE 8
#define NGX_HTTP_CACHE_KEY_LEN 16
@@ -143,6 +144,7 @@ void ngx_http_file_cache_create_key(ngx_http_request_t *r);
ngx_int_t ngx_http_file_cache_open(ngx_http_request_t *r);
void ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf);
void ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf);
+void ngx_http_file_cache_update_header(ngx_http_request_t *r);
ngx_int_t ngx_http_cache_send(ngx_http_request_t *);
void ngx_http_file_cache_free(ngx_http_cache_t *c, ngx_temp_file_t *tf);
time_t ngx_http_file_cache_valid(ngx_array_t *cache_valid, ngx_uint_t status);
diff --git a/usr.sbin/nginx/src/http/ngx_http_copy_filter_module.c b/usr.sbin/nginx/src/http/ngx_http_copy_filter_module.c
index 95bc0b83564..3ad27b0425b 100644
--- a/usr.sbin/nginx/src/http/ngx_http_copy_filter_module.c
+++ b/usr.sbin/nginx/src/http/ngx_http_copy_filter_module.c
@@ -169,13 +169,15 @@ ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in)
offset = c->busy_sendfile->file_pos;
if (file->aio) {
- c->aio_sendfile = (offset != file->aio->last_offset);
+ c->busy_count = (offset == file->aio->last_offset) ?
+ c->busy_count + 1 : 0;
file->aio->last_offset = offset;
- if (c->aio_sendfile == 0) {
+ if (c->busy_count > 2) {
ngx_log_error(NGX_LOG_ALERT, c->log, 0,
"sendfile(%V) returned busy again",
&file->name);
+ c->aio_sendfile = 0;
}
}
diff --git a/usr.sbin/nginx/src/http/ngx_http_core_module.c b/usr.sbin/nginx/src/http/ngx_http_core_module.c
index fbb1467ce16..a77ac3b20e1 100644
--- a/usr.sbin/nginx/src/http/ngx_http_core_module.c
+++ b/usr.sbin/nginx/src/http/ngx_http_core_module.c
@@ -1144,7 +1144,9 @@ ngx_http_core_access_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph)
}
if (rc == NGX_HTTP_FORBIDDEN || rc == NGX_HTTP_UNAUTHORIZED) {
- r->access_code = rc;
+ if (r->access_code != NGX_HTTP_UNAUTHORIZED) {
+ r->access_code = rc;
+ }
r->phase_handler++;
return NGX_AGAIN;
@@ -1462,9 +1464,6 @@ ngx_http_update_location_config(ngx_http_request_t *r)
if (r == r->main) {
ngx_http_set_connection_log(r->connection, clcf->error_log);
-#if (NGX_ENABLE_SYSLOG)
- r->connection->log->priority = clcf->error_log->priority;
-#endif
}
if ((ngx_io.flags & NGX_IO_SENDFILE) && clcf->sendfile) {
@@ -1936,6 +1935,12 @@ ngx_http_send_response(ngx_http_request_t *r, ngx_uint_t status,
ngx_int_t
ngx_http_send_header(ngx_http_request_t *r)
{
+ if (r->header_sent) {
+ ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+ "header already sent");
+ return NGX_ERROR;
+ }
+
if (r->err_status) {
r->headers_out.status = r->err_status;
r->headers_out.status_line.len = 0;
@@ -2019,7 +2024,9 @@ ngx_http_map_uri_to_path(ngx_http_request_t *r, ngx_str_t *path,
return NULL;
}
- if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, path, 0) != NGX_OK) {
+ if (ngx_get_full_name(r->pool, (ngx_str_t *) &ngx_cycle->prefix, path)
+ != NGX_OK)
+ {
return NULL;
}
@@ -2361,7 +2368,7 @@ equal:
}
-ngx_uint_t
+static ngx_uint_t
ngx_http_gzip_quantity(u_char *p, u_char *last)
{
u_char c;
@@ -2625,6 +2632,14 @@ ngx_http_named_location(ngx_http_request_t *r, ngx_str_t *name)
return NGX_DONE;
}
+ if (r->uri.len == 0) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "empty URI in redirect to named location \"%V\"", name);
+
+ ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+ return NGX_DONE;
+ }
+
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
if (cscf->named_locations) {
@@ -3034,9 +3049,12 @@ ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
#if (NGX_HAVE_SETFIB)
lsopt.setfib = -1;
#endif
+#if (NGX_HAVE_TCP_FASTOPEN)
+ lsopt.fastopen = -1;
+#endif
lsopt.wildcard = 1;
- (void) ngx_sock_ntop(&lsopt.u.sockaddr, lsopt.addr,
+ (void) ngx_sock_ntop(&lsopt.u.sockaddr, lsopt.socklen, lsopt.addr,
NGX_SOCKADDR_STRLEN, 1);
if (ngx_http_add_listen(cf, cscf, &lsopt) != NGX_OK) {
@@ -3214,9 +3232,9 @@ ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
#if (NGX_PCRE)
if (clcf->regex == NULL
- && ngx_strncmp(clcf->name.data, pclcf->name.data, len) != 0)
+ && ngx_filename_cmp(clcf->name.data, pclcf->name.data, len) != 0)
#else
- if (ngx_strncmp(clcf->name.data, pclcf->name.data, len) != 0)
+ if (ngx_filename_cmp(clcf->name.data, pclcf->name.data, len) != 0)
#endif
{
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -3414,25 +3432,16 @@ ngx_http_core_init_main_conf(ngx_conf_t *cf, void *conf)
{
ngx_http_core_main_conf_t *cmcf = conf;
- if (cmcf->server_names_hash_max_size == NGX_CONF_UNSET_UINT) {
- cmcf->server_names_hash_max_size = 512;
- }
-
- if (cmcf->server_names_hash_bucket_size == NGX_CONF_UNSET_UINT) {
- cmcf->server_names_hash_bucket_size = ngx_cacheline_size;
- }
+ ngx_conf_init_uint_value(cmcf->server_names_hash_max_size, 512);
+ ngx_conf_init_uint_value(cmcf->server_names_hash_bucket_size,
+ ngx_cacheline_size);
cmcf->server_names_hash_bucket_size =
ngx_align(cmcf->server_names_hash_bucket_size, ngx_cacheline_size);
- if (cmcf->variables_hash_max_size == NGX_CONF_UNSET_UINT) {
- cmcf->variables_hash_max_size = 512;
- }
-
- if (cmcf->variables_hash_bucket_size == NGX_CONF_UNSET_UINT) {
- cmcf->variables_hash_bucket_size = 64;
- }
+ ngx_conf_init_uint_value(cmcf->variables_hash_max_size, 1024);
+ ngx_conf_init_uint_value(cmcf->variables_hash_bucket_size, 64);
cmcf->variables_hash_bucket_size =
ngx_align(cmcf->variables_hash_bucket_size, ngx_cacheline_size);
@@ -3701,8 +3710,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
prev->types_hash_max_size, 1024);
ngx_conf_merge_uint_value(conf->types_hash_bucket_size,
- prev->types_hash_bucket_size,
- ngx_cacheline_size);
+ prev->types_hash_bucket_size, 64);
conf->types_hash_bucket_size = ngx_align(conf->types_hash_bucket_size,
ngx_cacheline_size);
@@ -3982,12 +3990,15 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
#if (NGX_HAVE_SETFIB)
lsopt.setfib = -1;
#endif
+#if (NGX_HAVE_TCP_FASTOPEN)
+ lsopt.fastopen = -1;
+#endif
lsopt.wildcard = u.wildcard;
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
lsopt.ipv6only = 1;
#endif
- (void) ngx_sock_ntop(&lsopt.u.sockaddr, lsopt.addr,
+ (void) ngx_sock_ntop(&lsopt.u.sockaddr, lsopt.socklen, lsopt.addr,
NGX_SOCKADDR_STRLEN, 1);
for (n = 2; n < cf->args->nelts; n++) {
@@ -4008,6 +4019,8 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
#if (NGX_HAVE_SETFIB)
if (ngx_strncmp(value[n].data, "setfib=", 7) == 0) {
lsopt.setfib = ngx_atoi(value[n].data + 7, value[n].len - 7);
+ lsopt.set = 1;
+ lsopt.bind = 1;
if (lsopt.setfib == NGX_ERROR) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -4018,6 +4031,23 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
continue;
}
#endif
+
+#if (NGX_HAVE_TCP_FASTOPEN)
+ if (ngx_strncmp(value[n].data, "fastopen=", 9) == 0) {
+ lsopt.fastopen = ngx_atoi(value[n].data + 9, value[n].len - 9);
+ lsopt.set = 1;
+ lsopt.bind = 1;
+
+ if (lsopt.fastopen == NGX_ERROR) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid fastopen \"%V\"", &value[n]);
+ return NGX_CONF_ERROR;
+ }
+
+ continue;
+ }
+#endif
+
if (ngx_strncmp(value[n].data, "backlog=", 8) == 0) {
lsopt.backlog = ngx_atoi(value[n].data + 8, value[n].len - 8);
lsopt.set = 1;
@@ -4247,6 +4277,11 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
#endif
}
+ if (ngx_strcmp(value[n].data, "proxy_protocol") == 0) {
+ lsopt.proxy_protocol = 1;
+ continue;
+ }
+
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid parameter \"%V\"", &value[n]);
return NGX_CONF_ERROR;
@@ -4476,7 +4511,7 @@ static ngx_http_method_name_t ngx_methods_names[] = {
{ (u_char *) "COPY", (uint32_t) ~NGX_HTTP_COPY },
{ (u_char *) "MOVE", (uint32_t) ~NGX_HTTP_MOVE },
{ (u_char *) "OPTIONS", (uint32_t) ~NGX_HTTP_OPTIONS },
- { (u_char *) "PROPFIND" , (uint32_t) ~NGX_HTTP_PROPFIND },
+ { (u_char *) "PROPFIND", (uint32_t) ~NGX_HTTP_PROPFIND },
{ (u_char *) "PROPPATCH", (uint32_t) ~NGX_HTTP_PROPPATCH },
{ (u_char *) "LOCK", (uint32_t) ~NGX_HTTP_LOCK },
{ (u_char *) "UNLOCK", (uint32_t) ~NGX_HTTP_UNLOCK },
@@ -4897,82 +4932,7 @@ ngx_http_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *clcf = conf;
- ngx_str_t *value, name;
-
-#if (NGX_ENABLE_SYSLOG)
- u_char *off = NULL;
- ngx_int_t syslog_on = 0;
- ngx_str_t priority;
-
- name = priority = (ngx_str_t) ngx_null_string;
-#endif
-
-
- if (clcf->error_log) {
- return "is duplicate";
- }
-
- value = cf->args->elts;
-
- if (ngx_strcmp(value[1].data, "stderr") == 0) {
- ngx_str_null(&name);
-
-#if (NGX_ENABLE_SYSLOG)
- } else if (ngx_strncmp(value[1].data, "syslog", sizeof("syslog") - 1) == 0) {
- if (!cf->cycle->new_log.syslog_set) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "You must set the syslog directive and enable it first.");
- return NGX_CONF_ERROR;
- }
-
- syslog_on = 1;
-
- if (value[1].data[sizeof("syslog") - 1] == ':') {
- priority.len = value[1].len - sizeof("syslog");
- priority.data = value[1].data + sizeof("syslog");
-
- off = (u_char*) ngx_strchr(priority.data, '|');
- if (off != NULL) {
- priority.len = off - priority.data;
-
- off++;
- name.len = value[1].data + value[1].len - off;
- name.data = off;
- }
- }
- else {
- if (value[1].len > sizeof("syslog")) {
- name.len = value[1].len - sizeof("syslog");
- name.data = value[1].data + sizeof("syslog");
- }
- }
-#endif
- } else {
- name = value[1];
- }
-
- clcf->error_log = ngx_log_create(cf->cycle, &name);
- if (clcf->error_log == NULL) {
- return NGX_CONF_ERROR;
- }
-
-#if (NGX_ENABLE_SYSLOG)
- if (syslog_on) {
- clcf->error_log->syslog_on = 1;
- if (ngx_log_set_priority(cf, &priority, clcf->error_log) == NGX_CONF_ERROR) {
- return NGX_CONF_ERROR;
- }
- }
-
- clcf->error_log->log_level = 0;
-#endif
-
- if (cf->args->nelts == 2) {
- clcf->error_log->log_level = NGX_LOG_ERR;
- return NGX_CONF_OK;
- }
-
- return ngx_log_set_levels(cf, clcf->error_log);
+ return ngx_log_set_log(cf, &clcf->error_log);
}
diff --git a/usr.sbin/nginx/src/http/ngx_http_core_module.h b/usr.sbin/nginx/src/http/ngx_http_core_module.h
index 5b38000d8db..799d2fe0dd5 100644
--- a/usr.sbin/nginx/src/http/ngx_http_core_module.h
+++ b/usr.sbin/nginx/src/http/ngx_http_core_module.h
@@ -82,6 +82,7 @@ typedef struct {
unsigned ipv6only:1;
#endif
unsigned so_keepalive:2;
+ unsigned proxy_protocol:1;
int backlog;
int rcvbuf;
@@ -89,6 +90,9 @@ typedef struct {
#if (NGX_HAVE_SETFIB)
int setfib;
#endif
+#if (NGX_HAVE_TCP_FASTOPEN)
+ int fastopen;
+#endif
#if (NGX_HAVE_KEEPALIVE_TUNABLE)
int tcp_keepidle;
int tcp_keepintvl;
@@ -240,6 +244,7 @@ struct ngx_http_addr_conf_s {
#if (NGX_HTTP_SPDY)
unsigned spdy:1;
#endif
+ unsigned proxy_protocol:1;
};
diff --git a/usr.sbin/nginx/src/http/ngx_http_file_cache.c b/usr.sbin/nginx/src/http/ngx_http_file_cache.c
index 6d94c503425..9e6be15844a 100644
--- a/usr.sbin/nginx/src/http/ngx_http_file_cache.c
+++ b/usr.sbin/nginx/src/http/ngx_http_file_cache.c
@@ -53,6 +53,7 @@ ngx_str_t ngx_http_cache_status[] = {
ngx_string("EXPIRED"),
ngx_string("STALE"),
ngx_string("UPDATING"),
+ ngx_string("REVALIDATED"),
ngx_string("HIT")
};
@@ -445,8 +446,7 @@ ngx_http_file_cache_lock_wait_handler(ngx_event_t *ev)
timer = c->wait_time - ngx_current_msec;
if ((ngx_msec_int_t) timer <= 0) {
- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
- "http file cache lock timeout");
+ ngx_log_error(NGX_LOG_INFO, ev->log, 0, "cache lock timeout");
c->lock = 0;
goto wakeup;
}
@@ -504,7 +504,7 @@ ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c)
return NGX_DECLINED;
}
- if (h->body_start > c->body_start) {
+ if ((size_t) h->body_start > c->body_start) {
ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
"cache file \"%s\" has too long header",
c->file.name.data);
@@ -875,6 +875,8 @@ ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf)
c = r->cache;
+ ngx_memzero(h, sizeof(ngx_http_file_cache_header_t));
+
h->valid_sec = c->valid_sec;
h->last_modified = c->last_modified;
h->date = c->date;
@@ -970,6 +972,116 @@ ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf)
}
+void
+ngx_http_file_cache_update_header(ngx_http_request_t *r)
+{
+ ssize_t n;
+ ngx_err_t err;
+ ngx_file_t file;
+ ngx_file_info_t fi;
+ ngx_http_cache_t *c;
+ ngx_http_file_cache_header_t h;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http file cache update header");
+
+ c = r->cache;
+
+ ngx_memzero(&file, sizeof(ngx_file_t));
+
+ file.name = c->file.name;
+ file.log = r->connection->log;
+ file.fd = ngx_open_file(file.name.data, NGX_FILE_RDWR, NGX_FILE_OPEN, 0);
+
+ if (file.fd == NGX_INVALID_FILE) {
+ err = ngx_errno;
+
+ /* cache file may have been deleted */
+
+ if (err == NGX_ENOENT) {
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http file cache \"%s\" not found",
+ file.name.data);
+ return;
+ }
+
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
+ ngx_open_file_n " \"%s\" failed", file.name.data);
+ return;
+ }
+
+ /*
+ * make sure cache file wasn't replaced;
+ * if it was, do nothing
+ */
+
+ if (ngx_fd_info(file.fd, &fi) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
+ ngx_fd_info_n " \"%s\" failed", file.name.data);
+ goto done;
+ }
+
+ if (c->uniq != ngx_file_uniq(&fi)
+ || c->length != ngx_file_size(&fi))
+ {
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http file cache \"%s\" changed",
+ file.name.data);
+ goto done;
+ }
+
+ n = ngx_read_file(&file, (u_char *) &h,
+ sizeof(ngx_http_file_cache_header_t), 0);
+
+ if (n == NGX_ERROR) {
+ goto done;
+ }
+
+ if ((size_t) n != sizeof(ngx_http_file_cache_header_t)) {
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
+ ngx_read_file_n " read only %z of %z from \"%s\"",
+ n, sizeof(ngx_http_file_cache_header_t), file.name.data);
+ goto done;
+ }
+
+ if (h.last_modified != c->last_modified
+ || h.crc32 != c->crc32
+ || h.header_start != c->header_start
+ || h.body_start != c->body_start)
+ {
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http file cache \"%s\" content changed",
+ file.name.data);
+ goto done;
+ }
+
+ /*
+ * update cache file header with new data,
+ * notably h.valid_sec and h.date
+ */
+
+ ngx_memzero(&h, sizeof(ngx_http_file_cache_header_t));
+
+ h.valid_sec = c->valid_sec;
+ h.last_modified = c->last_modified;
+ h.date = c->date;
+ h.crc32 = c->crc32;
+ h.valid_msec = (u_short) c->valid_msec;
+ h.header_start = (u_short) c->header_start;
+ h.body_start = (u_short) c->body_start;
+
+ (void) ngx_write_file(&file, (u_char *) &h,
+ sizeof(ngx_http_file_cache_header_t), 0);
+
+done:
+
+ if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed", file.name.data);
+ }
+}
+
+
ngx_int_t
ngx_http_cache_send(ngx_http_request_t *r)
{
diff --git a/usr.sbin/nginx/src/http/ngx_http_header_filter_module.c b/usr.sbin/nginx/src/http/ngx_http_header_filter_module.c
index 707a8131353..507dc939c78 100644
--- a/usr.sbin/nginx/src/http/ngx_http_header_filter_module.c
+++ b/usr.sbin/nginx/src/http/ngx_http_header_filter_module.c
@@ -92,10 +92,7 @@ static ngx_str_t ngx_http_status_lines[] = {
ngx_string("411 Length Required"),
ngx_string("412 Precondition Failed"),
ngx_string("413 Request Entity Too Large"),
- ngx_null_string, /* "414 Request-URI Too Large", but we never send it
- * because we treat such requests as the HTTP/0.9
- * requests and send only a body without a header
- */
+ ngx_string("414 Request-URI Too Large"),
ngx_string("415 Unsupported Media Type"),
ngx_string("416 Requested Range Not Satisfiable"),
@@ -267,7 +264,13 @@ ngx_http_header_filter(ngx_http_request_t *r)
len += ngx_http_status_lines[status].len;
} else {
- len += NGX_INT_T_LEN;
+ len += NGX_INT_T_LEN + 1 /* SP */;
+ status_line = NULL;
+ }
+
+ if (status_line && status_line->len == 0) {
+ status = r->headers_out.status;
+ len += NGX_INT_T_LEN + 1 /* SP */;
status_line = NULL;
}
}
@@ -448,7 +451,7 @@ ngx_http_header_filter(ngx_http_request_t *r)
b->last = ngx_copy(b->last, status_line->data, status_line->len);
} else {
- b->last = ngx_sprintf(b->last, "%03ui", status);
+ b->last = ngx_sprintf(b->last, "%03ui ", status);
}
*b->last++ = CR; *b->last++ = LF;
diff --git a/usr.sbin/nginx/src/http/ngx_http_parse.c b/usr.sbin/nginx/src/http/ngx_http_parse.c
index f8d5910ddef..02b4a0fd109 100644
--- a/usr.sbin/nginx/src/http/ngx_http_parse.c
+++ b/usr.sbin/nginx/src/http/ngx_http_parse.c
@@ -212,14 +212,17 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
case 5:
if (ngx_str5cmp(m, 'M', 'K', 'C', 'O', 'L')) {
r->method = NGX_HTTP_MKCOL;
+ break;
}
if (ngx_str5cmp(m, 'P', 'A', 'T', 'C', 'H')) {
r->method = NGX_HTTP_PATCH;
+ break;
}
if (ngx_str5cmp(m, 'T', 'R', 'A', 'C', 'E')) {
r->method = NGX_HTTP_TRACE;
+ break;
}
break;
@@ -883,6 +886,19 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b,
break;
}
+ if (ch == '_') {
+ if (allow_underscores) {
+ hash = ngx_hash(0, ch);
+ r->lowcase_header[0] = ch;
+ i = 1;
+
+ } else {
+ r->invalid_header = 1;
+ }
+
+ break;
+ }
+
if (ch == '\0') {
return NGX_HTTP_PARSE_INVALID_HEADER;
}
@@ -1258,8 +1274,8 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes)
* the line feed
*/
- ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "s:%d in:'%Xd:%c', out:'%c'", state, ch, ch, *u);
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "s:%d in:'%Xd:%c'", state, ch, ch);
switch (state) {
@@ -1777,17 +1793,21 @@ ngx_int_t
ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri,
ngx_str_t *args, ngx_uint_t *flags)
{
- u_char ch, *p;
- size_t len;
+ u_char ch, *p, *src, *dst;
+ size_t len;
+ ngx_uint_t quoted;
len = uri->len;
p = uri->data;
+ quoted = 0;
if (len == 0 || p[0] == '?') {
goto unsafe;
}
- if (p[0] == '.' && len == 3 && p[1] == '.' && (ngx_path_separator(p[2]))) {
+ if (p[0] == '.' && len > 1 && p[1] == '.'
+ && (len == 2 || ngx_path_separator(p[2])))
+ {
goto unsafe;
}
@@ -1795,6 +1815,11 @@ ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri,
ch = *p++;
+ if (ch == '%') {
+ quoted = 1;
+ continue;
+ }
+
if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
continue;
}
@@ -1804,7 +1829,7 @@ ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri,
args->data = p;
uri->len -= len;
- return NGX_OK;
+ break;
}
if (ch == '\0') {
@@ -1813,14 +1838,66 @@ ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri,
if (ngx_path_separator(ch) && len > 2) {
- /* detect "/../" */
+ /* detect "/../" and "/.." */
- if (p[0] == '.' && p[1] == '.' && ngx_path_separator(p[2])) {
+ if (p[0] == '.' && p[1] == '.'
+ && (len == 3 || ngx_path_separator(p[2])))
+ {
goto unsafe;
}
}
}
+ if (quoted) {
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "escaped URI: \"%V\"", uri);
+
+ src = uri->data;
+
+ dst = ngx_pnalloc(r->pool, uri->len);
+ if (dst == NULL) {
+ return NGX_ERROR;
+ }
+
+ uri->data = dst;
+
+ ngx_unescape_uri(&dst, &src, uri->len, 0);
+
+ uri->len = dst - uri->data;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "unescaped URI: \"%V\"", uri);
+
+ len = uri->len;
+ p = uri->data;
+
+ if (p[0] == '.' && len > 1 && p[1] == '.'
+ && (len == 2 || ngx_path_separator(p[2])))
+ {
+ goto unsafe;
+ }
+
+ for ( /* void */ ; len; len--) {
+
+ ch = *p++;
+
+ if (ch == '\0') {
+ goto unsafe;
+ }
+
+ if (ngx_path_separator(ch) && len > 2) {
+
+ /* detect "/../" and "/.." */
+
+ if (p[0] == '.' && p[1] == '.'
+ && (len == 3 || ngx_path_separator(p[2])))
+ {
+ goto unsafe;
+ }
+ }
+ }
+ }
+
return NGX_OK;
unsafe:
@@ -2182,8 +2259,9 @@ data:
ctx->length = 3 /* "0" LF LF */;
break;
case sw_chunk_size:
- ctx->length = 2 /* LF LF */
- + (ctx->size ? ctx->size + 4 /* LF "0" LF LF */ : 0);
+ ctx->length = 1 /* LF */
+ + (ctx->size ? ctx->size + 4 /* LF "0" LF LF */
+ : 1 /* LF */);
break;
case sw_chunk_extension:
case sw_chunk_extension_almost_done:
diff --git a/usr.sbin/nginx/src/http/ngx_http_postpone_filter_module.c b/usr.sbin/nginx/src/http/ngx_http_postpone_filter_module.c
index 85c4b84d027..e893b836488 100644
--- a/usr.sbin/nginx/src/http/ngx_http_postpone_filter_module.c
+++ b/usr.sbin/nginx/src/http/ngx_http_postpone_filter_module.c
@@ -70,8 +70,7 @@ ngx_http_postpone_filter(ngx_http_request_t *r, ngx_chain_t *in)
#if 0
/* TODO: SSI may pass NULL */
ngx_log_error(NGX_LOG_ALERT, c->log, 0,
- "http postpone filter NULL inactive request",
- &r->uri, &r->args);
+ "http postpone filter NULL inactive request");
#endif
return NGX_OK;
@@ -108,8 +107,7 @@ ngx_http_postpone_filter(ngx_http_request_t *r, ngx_chain_t *in)
if (pr->out == NULL) {
ngx_log_error(NGX_LOG_ALERT, c->log, 0,
- "http postpone filter NULL output",
- &r->uri, &r->args);
+ "http postpone filter NULL output");
} else {
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
diff --git a/usr.sbin/nginx/src/http/ngx_http_request.c b/usr.sbin/nginx/src/http/ngx_http_request.c
index dcebc370862..4bf9d1fcf1c 100644
--- a/usr.sbin/nginx/src/http/ngx_http_request.c
+++ b/usr.sbin/nginx/src/http/ngx_http_request.c
@@ -343,6 +343,11 @@ ngx_http_init_connection(ngx_connection_t *c)
}
#endif
+ if (hc->addr_conf->proxy_protocol) {
+ hc->proxy_protocol = 1;
+ c->log->action = "reading PROXY protocol";
+ }
+
if (rev->ready) {
/* the deferred accept(), rtsig, aio, iocp */
@@ -368,6 +373,7 @@ ngx_http_init_connection(ngx_connection_t *c)
static void
ngx_http_wait_request_handler(ngx_event_t *rev)
{
+ u_char *p;
size_t size;
ssize_t n;
ngx_buf_t *b;
@@ -458,6 +464,27 @@ ngx_http_wait_request_handler(ngx_event_t *rev)
b->last += n;
+ if (hc->proxy_protocol) {
+ hc->proxy_protocol = 0;
+
+ p = ngx_proxy_protocol_parse(c, b->pos, b->last);
+
+ if (p == NULL) {
+ ngx_http_close_connection(c);
+ return;
+ }
+
+ b->pos = p;
+
+ if (b->pos == b->last) {
+ c->log->action = "waiting for request";
+ b->pos = b->start;
+ b->last = b->start;
+ ngx_post_event(rev, &ngx_posted_events);
+ return;
+ }
+ }
+
c->log->action = "reading client request line";
ngx_reusable_connection(c, 0);
@@ -517,9 +544,6 @@ ngx_http_create_request(ngx_connection_t *c)
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
ngx_http_set_connection_log(r->connection, clcf->error_log);
-#if (NGX_ENABLE_SYSLOG)
- c->log->priority = clcf->error_log->priority;
-#endif
r->header_in = hc->nbusy ? hc->busy[0] : c->buffer;
@@ -560,6 +584,7 @@ ngx_http_create_request(ngx_connection_t *c)
r->start_msec = tp->msec;
r->method = NGX_HTTP_UNKNOWN;
+ r->http_version = NGX_HTTP_VERSION_10;
r->headers_in.content_length_n = -1;
r->headers_in.keep_alive_n = -1;
@@ -591,7 +616,8 @@ ngx_http_create_request(ngx_connection_t *c)
static void
ngx_http_ssl_handshake(ngx_event_t *rev)
{
- u_char buf[1];
+ u_char *p, buf[NGX_PROXY_PROTOCOL_MAX_HEADER + 1];
+ size_t size;
ssize_t n;
ngx_err_t err;
ngx_int_t rc;
@@ -600,6 +626,7 @@ ngx_http_ssl_handshake(ngx_event_t *rev)
ngx_http_ssl_srv_conf_t *sscf;
c = rev->data;
+ hc = c->data;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
"http check ssl handshake");
@@ -615,7 +642,9 @@ ngx_http_ssl_handshake(ngx_event_t *rev)
return;
}
- n = recv(c->fd, (char *) buf, 1, MSG_PEEK);
+ size = hc->proxy_protocol ? sizeof(buf) : 1;
+
+ n = recv(c->fd, (char *) buf, size, MSG_PEEK);
err = ngx_socket_errno;
@@ -642,12 +671,39 @@ ngx_http_ssl_handshake(ngx_event_t *rev)
return;
}
+ if (hc->proxy_protocol) {
+ hc->proxy_protocol = 0;
+
+ p = ngx_proxy_protocol_parse(c, buf, buf + n);
+
+ if (p == NULL) {
+ ngx_http_close_connection(c);
+ return;
+ }
+
+ size = p - buf;
+
+ if (c->recv(c, buf, size) != (ssize_t) size) {
+ ngx_http_close_connection(c);
+ return;
+ }
+
+ c->log->action = "SSL handshaking";
+
+ if (n == (ssize_t) size) {
+ ngx_post_event(rev, &ngx_posted_events);
+ return;
+ }
+
+ n = 1;
+ buf[0] = *p;
+ }
+
if (n == 1) {
if (buf[0] & 0x80 /* SSLv2 */ || buf[0] == 0x16 /* SSLv3/TLSv1 */) {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0,
"https ssl handshake: 0x%02Xd", buf[0]);
- hc = c->data;
sscf = ngx_http_get_module_srv_conf(hc->conf_ctx,
ngx_http_ssl_module);
@@ -707,13 +763,26 @@ ngx_http_ssl_handshake_handler(ngx_connection_t *c)
c->ssl->no_wait_shutdown = 1;
-#if (NGX_HTTP_SPDY && defined TLSEXT_TYPE_next_proto_neg)
+#if (NGX_HTTP_SPDY \
+ && (defined TLSEXT_TYPE_application_layer_protocol_negotiation \
+ || defined TLSEXT_TYPE_next_proto_neg))
{
unsigned int len;
const unsigned char *data;
static const ngx_str_t spdy = ngx_string(NGX_SPDY_NPN_NEGOTIATED);
+#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
+ SSL_get0_alpn_selected(c->ssl->connection, &data, &len);
+
+#ifdef TLSEXT_TYPE_next_proto_neg
+ if (len == 0) {
+ SSL_get0_next_proto_negotiated(c->ssl->connection, &data, &len);
+ }
+#endif
+
+#else /* TLSEXT_TYPE_next_proto_neg */
SSL_get0_next_proto_negotiated(c->ssl->connection, &data, &len);
+#endif
if (len == spdy.len && ngx_strncmp(data, spdy.data, spdy.len) == 0) {
ngx_http_spdy_init(c->read);
@@ -798,9 +867,6 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg)
clcf = ngx_http_get_module_loc_conf(hc->conf_ctx, ngx_http_core_module);
ngx_http_set_connection_log(c, clcf->error_log);
-#if (NGX_ENABLE_SYSLOG)
- c->log->priority = clcf->error_log->priority;
-#endif
sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module);
@@ -1936,6 +2002,10 @@ ngx_http_set_virtual_server(ngx_http_request_t *r, ngx_str_t *host)
ngx_http_core_loc_conf_t *clcf;
ngx_http_core_srv_conf_t *cscf;
+#if (NGX_SUPPRESS_WARN)
+ cscf = NULL;
+#endif
+
hc = r->http_connection;
#if (NGX_HTTP_SSL && defined SSL_CTRL_SET_TLSEXT_HOSTNAME)
@@ -2002,9 +2072,6 @@ ngx_http_set_virtual_server(ngx_http_request_t *r, ngx_str_t *host)
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
ngx_http_set_connection_log(r->connection, clcf->error_log);
-#if (NGX_ENABLE_SYSLOG)
- r->connection->log->priority = clcf->error_log->priority;
-#endif
return NGX_OK;
}
@@ -2679,6 +2746,33 @@ ngx_http_test_reading(ngx_http_request_t *r)
#endif
+#if (NGX_HAVE_EPOLLRDHUP)
+
+ if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && rev->pending_eof) {
+ socklen_t len;
+
+ rev->eof = 1;
+ c->error = 1;
+
+ err = 0;
+ len = sizeof(ngx_err_t);
+
+ /*
+ * BSDs and Linux return 0 and set a pending error in err
+ * Solaris returns -1 and sets errno
+ */
+
+ if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len)
+ == -1)
+ {
+ err = ngx_socket_errno;
+ }
+
+ goto closed;
+ }
+
+#endif
+
n = recv(c->fd, buf, 1, MSG_PEEK);
if (n == 0) {
@@ -2719,7 +2813,7 @@ closed:
ngx_log_error(NGX_LOG_INFO, c->log, err,
"client prematurely closed connection");
- ngx_http_finalize_request(r, 0);
+ ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST);
}
@@ -3152,8 +3246,8 @@ ngx_http_lingering_close_handler(ngx_event_t *rev)
return;
}
- timer = (ngx_msec_t) (r->lingering_time - ngx_time());
- if (timer <= 0) {
+ timer = (ngx_msec_t) r->lingering_time - (ngx_msec_t) ngx_time();
+ if ((ngx_msec_int_t) timer <= 0) {
ngx_http_close_request(r, 0);
return;
}
@@ -3328,10 +3422,15 @@ ngx_http_free_request(ngx_http_request_t *r, ngx_int_t rc)
return;
}
- for (cln = r->cleanup; cln; cln = cln->next) {
+ cln = r->cleanup;
+ r->cleanup = NULL;
+
+ while (cln) {
if (cln->handler) {
cln->handler(cln->data);
}
+
+ cln = cln->next;
}
#if (NGX_STAT_STUB)
diff --git a/usr.sbin/nginx/src/http/ngx_http_request.h b/usr.sbin/nginx/src/http/ngx_http_request.h
index bd842df7e3f..e4a4944fe44 100644
--- a/usr.sbin/nginx/src/http/ngx_http_request.h
+++ b/usr.sbin/nginx/src/http/ngx_http_request.h
@@ -309,8 +309,9 @@ typedef struct {
ngx_int_t nfree;
#if (NGX_HTTP_SSL)
- ngx_uint_t ssl; /* unsigned ssl:1; */
+ unsigned ssl:1;
#endif
+ unsigned proxy_protocol:1;
} ngx_http_connection_t;
@@ -420,6 +421,7 @@ struct ngx_http_request_s {
#endif
size_t limit_rate;
+ size_t limit_rate_after;
/* used to learn the Apache compatible response length without a header */
size_t header_size;
@@ -526,6 +528,7 @@ struct ngx_http_request_s {
unsigned filter_need_in_memory:1;
unsigned filter_need_temporary:1;
unsigned allow_ranges:1;
+ unsigned single_range:1;
#if (NGX_STAT_STUB)
unsigned stat_reading:1;
@@ -584,6 +587,9 @@ extern ngx_http_header_out_t ngx_http_headers_out[];
#define ngx_http_set_connection_log(c, l) \
\
c->log->file = l->file; \
+ c->log->next = l->next; \
+ c->log->writer = l->writer; \
+ c->log->wdata = l->wdata; \
if (!(c->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { \
c->log->log_level = l->log_level; \
}
diff --git a/usr.sbin/nginx/src/http/ngx_http_request_body.c b/usr.sbin/nginx/src/http/ngx_http_request_body.c
index e9cf3e93007..bbf16fd2576 100644
--- a/usr.sbin/nginx/src/http/ngx_http_request_body.c
+++ b/usr.sbin/nginx/src/http/ngx_http_request_body.c
@@ -43,7 +43,7 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
r->main->count++;
#if (NGX_HTTP_SPDY)
- if (r->spdy_stream) {
+ if (r->spdy_stream && r == r->main) {
rc = ngx_http_spdy_read_request_body(r, post_handler);
goto done;
}
@@ -582,9 +582,9 @@ ngx_http_discarded_request_body_handler(ngx_http_request_t *r)
}
if (r->lingering_time) {
- timer = (ngx_msec_t) (r->lingering_time - ngx_time());
+ timer = (ngx_msec_t) r->lingering_time - (ngx_msec_t) ngx_time();
- if (timer <= 0) {
+ if ((ngx_msec_int_t) timer <= 0) {
r->discard_body = 0;
r->lingering_close = 0;
ngx_http_finalize_request(r, NGX_ERROR);
@@ -726,7 +726,7 @@ ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b)
size = b->last - b->pos;
if ((off_t) size > rb->chunked->size) {
- b->pos += rb->chunked->size;
+ b->pos += (size_t) rb->chunked->size;
rb->chunked->size = 0;
} else {
@@ -765,7 +765,7 @@ ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b)
size = b->last - b->pos;
if ((off_t) size > r->headers_in.content_length_n) {
- b->pos += r->headers_in.content_length_n;
+ b->pos += (size_t) r->headers_in.content_length_n;
r->headers_in.content_length_n = 0;
} else {
@@ -882,7 +882,7 @@ ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in)
rb->rest -= size;
} else {
- cl->buf->pos += rb->rest;
+ cl->buf->pos += (size_t) rb->rest;
rb->rest = 0;
b->last = cl->buf->pos;
b->last_buf = 1;
@@ -988,7 +988,7 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
size = cl->buf->last - cl->buf->pos;
if ((off_t) size > rb->chunked->size) {
- cl->buf->pos += rb->chunked->size;
+ cl->buf->pos += (size_t) rb->chunked->size;
r->headers_in.content_length_n += rb->chunked->size;
rb->chunked->size = 0;
diff --git a/usr.sbin/nginx/src/http/ngx_http_script.c b/usr.sbin/nginx/src/http/ngx_http_script.c
index 54d019589a9..02e2be3bb80 100644
--- a/usr.sbin/nginx/src/http/ngx_http_script.c
+++ b/usr.sbin/nginx/src/http/ngx_http_script.c
@@ -1327,16 +1327,17 @@ ngx_http_script_full_name_code(ngx_http_script_engine_t *e)
{
ngx_http_script_full_name_code_t *code;
- ngx_str_t value;
+ ngx_str_t value, *prefix;
code = (ngx_http_script_full_name_code_t *) e->ip;
value.data = e->buf.data;
value.len = e->pos - e->buf.data;
- if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &value, code->conf_prefix)
- != NGX_OK)
- {
+ prefix = code->conf_prefix ? (ngx_str_t *) &ngx_cycle->conf_prefix:
+ (ngx_str_t *) &ngx_cycle->prefix;
+
+ if (ngx_get_full_name(e->request->pool, prefix, &value) != NGX_OK) {
e->ip = ngx_http_script_exit;
e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
return;
@@ -1393,7 +1394,7 @@ ngx_http_script_if_code(ngx_http_script_engine_t *e)
e->sp--;
- if (e->sp->len && (e->sp->len !=1 || e->sp->data[0] != '0')) {
+ if (e->sp->len && (e->sp->len != 1 || e->sp->data[0] != '0')) {
if (code->loc_conf) {
e->request->loc_conf = code->loc_conf;
ngx_http_update_location_config(e->request);
diff --git a/usr.sbin/nginx/src/http/ngx_http_spdy.c b/usr.sbin/nginx/src/http/ngx_http_spdy.c
index 99afbfca180..9bd624c82bc 100644
--- a/usr.sbin/nginx/src/http/ngx_http_spdy.c
+++ b/usr.sbin/nginx/src/http/ngx_http_spdy.c
@@ -42,16 +42,19 @@
#define ngx_spdy_frame_parse_sid(p) \
(ngx_spdy_frame_parse_uint32(p) & 0x7fffffff)
+#define ngx_spdy_frame_parse_delta(p) \
+ (ngx_spdy_frame_parse_uint32(p) & 0x7fffffff)
#define ngx_spdy_ctl_frame_check(h) \
- (((h) & 0xffffff00) == ngx_spdy_ctl_frame_head(0))
+ (((h) & 0xffff0000) == ngx_spdy_ctl_frame_head(0))
#define ngx_spdy_data_frame_check(h) \
(!((h) & (uint32_t) NGX_SPDY_CTL_BIT << 31))
-#define ngx_spdy_ctl_frame_type(h) ((h) & 0x000000ff)
+#define ngx_spdy_ctl_frame_type(h) ((h) & 0x0000ffff)
#define ngx_spdy_frame_flags(p) ((p) >> 24)
#define ngx_spdy_frame_length(p) ((p) & 0x00ffffff)
+#define ngx_spdy_frame_id(p) ((p) & 0x00ffffff)
#define NGX_SPDY_SKIP_HEADERS_BUFFER_SIZE 4096
@@ -64,10 +67,21 @@
#define NGX_SPDY_CANCEL 5
#define NGX_SPDY_INTERNAL_ERROR 6
#define NGX_SPDY_FLOW_CONTROL_ERROR 7
+#define NGX_SPDY_STREAM_IN_USE 8
+#define NGX_SPDY_STREAM_ALREADY_CLOSED 9
+/* deprecated 10 */
+#define NGX_SPDY_FRAME_TOO_LARGE 11
#define NGX_SPDY_SETTINGS_MAX_STREAMS 4
+#define NGX_SPDY_SETTINGS_INIT_WINDOW 7
#define NGX_SPDY_SETTINGS_FLAG_PERSIST 0x01
+#define NGX_SPDY_SETTINGS_FLAG_PERSISTED 0x02
+
+#define NGX_SPDY_MAX_WINDOW NGX_MAX_INT32_VALUE
+#define NGX_SPDY_CONNECTION_WINDOW 65536
+#define NGX_SPDY_INIT_STREAM_WINDOW 65536
+#define NGX_SPDY_STREAM_WINDOW NGX_SPDY_MAX_WINDOW
typedef struct {
ngx_uint_t hash;
@@ -81,8 +95,8 @@ static void ngx_http_spdy_read_handler(ngx_event_t *rev);
static void ngx_http_spdy_write_handler(ngx_event_t *wev);
static void ngx_http_spdy_handle_connection(ngx_http_spdy_connection_t *sc);
-static u_char *ngx_http_spdy_state_detect_settings(
- ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end);
+static u_char *ngx_http_spdy_proxy_protocol(ngx_http_spdy_connection_t *sc,
+ u_char *pos, u_char *end);
static u_char *ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc,
u_char *pos, u_char *end);
static u_char *ngx_http_spdy_state_syn_stream(ngx_http_spdy_connection_t *sc,
@@ -93,8 +107,12 @@ static u_char *ngx_http_spdy_state_headers_error(ngx_http_spdy_connection_t *sc,
u_char *pos, u_char *end);
static u_char *ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc,
u_char *pos, u_char *end);
+static u_char *ngx_http_spdy_state_window_update(ngx_http_spdy_connection_t *sc,
+ u_char *pos, u_char *end);
static u_char *ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc,
u_char *pos, u_char *end);
+static u_char *ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc,
+ u_char *pos, u_char *end);
static u_char *ngx_http_spdy_state_rst_stream(ngx_http_spdy_connection_t *sc,
u_char *pos, u_char *end);
static u_char *ngx_http_spdy_state_ping(ngx_http_spdy_connection_t *sc,
@@ -103,8 +121,6 @@ static u_char *ngx_http_spdy_state_skip(ngx_http_spdy_connection_t *sc,
u_char *pos, u_char *end);
static u_char *ngx_http_spdy_state_settings(ngx_http_spdy_connection_t *sc,
u_char *pos, u_char *end);
-static u_char *ngx_http_spdy_state_noop(ngx_http_spdy_connection_t *sc,
- u_char *pos, u_char *end);
static u_char *ngx_http_spdy_state_complete(ngx_http_spdy_connection_t *sc,
u_char *pos, u_char *end);
static u_char *ngx_http_spdy_state_save(ngx_http_spdy_connection_t *sc,
@@ -114,6 +130,8 @@ static u_char *ngx_http_spdy_state_protocol_error(
static u_char *ngx_http_spdy_state_internal_error(
ngx_http_spdy_connection_t *sc);
+static ngx_int_t ngx_http_spdy_send_window_update(
+ ngx_http_spdy_connection_t *sc, ngx_uint_t sid, ngx_uint_t delta);
static ngx_int_t ngx_http_spdy_send_rst_stream(ngx_http_spdy_connection_t *sc,
ngx_uint_t sid, ngx_uint_t status, ngx_uint_t priority);
static ngx_int_t ngx_http_spdy_send_settings(ngx_http_spdy_connection_t *sc);
@@ -138,55 +156,220 @@ static ngx_int_t ngx_http_spdy_alloc_large_header_buffer(ngx_http_request_t *r);
static ngx_int_t ngx_http_spdy_handle_request_header(ngx_http_request_t *r);
static ngx_int_t ngx_http_spdy_parse_method(ngx_http_request_t *r);
static ngx_int_t ngx_http_spdy_parse_scheme(ngx_http_request_t *r);
-static ngx_int_t ngx_http_spdy_parse_url(ngx_http_request_t *r);
+static ngx_int_t ngx_http_spdy_parse_host(ngx_http_request_t *r);
+static ngx_int_t ngx_http_spdy_parse_path(ngx_http_request_t *r);
static ngx_int_t ngx_http_spdy_parse_version(ngx_http_request_t *r);
static ngx_int_t ngx_http_spdy_construct_request_line(ngx_http_request_t *r);
static void ngx_http_spdy_run_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_spdy_init_request_body(ngx_http_request_t *r);
+static ngx_int_t ngx_http_spdy_terminate_stream(ngx_http_spdy_connection_t *sc,
+ ngx_http_spdy_stream_t *stream, ngx_uint_t status);
+
+static void ngx_http_spdy_close_stream_handler(ngx_event_t *ev);
+
static void ngx_http_spdy_handle_connection_handler(ngx_event_t *rev);
static void ngx_http_spdy_keepalive_handler(ngx_event_t *rev);
static void ngx_http_spdy_finalize_connection(ngx_http_spdy_connection_t *sc,
ngx_int_t rc);
+static ngx_int_t ngx_http_spdy_adjust_windows(ngx_http_spdy_connection_t *sc,
+ ssize_t delta);
+
static void ngx_http_spdy_pool_cleanup(void *data);
static void *ngx_http_spdy_zalloc(void *opaque, u_int items, u_int size);
static void ngx_http_spdy_zfree(void *opaque, void *address);
-static const u_char ngx_http_spdy_dict[] =
- "options" "get" "head" "post" "put" "delete" "trace"
- "accept" "accept-charset" "accept-encoding" "accept-language"
- "authorization" "expect" "from" "host"
- "if-modified-since" "if-match" "if-none-match" "if-range"
- "if-unmodifiedsince" "max-forwards" "proxy-authorization"
- "range" "referer" "te" "user-agent"
- "100" "101" "200" "201" "202" "203" "204" "205" "206"
- "300" "301" "302" "303" "304" "305" "306" "307"
- "400" "401" "402" "403" "404" "405" "406" "407" "408" "409" "410"
- "411" "412" "413" "414" "415" "416" "417"
- "500" "501" "502" "503" "504" "505"
- "accept-ranges" "age" "etag" "location" "proxy-authenticate" "public"
- "retry-after" "server" "vary" "warning" "www-authenticate" "allow"
- "content-base" "content-encoding" "cache-control" "connection" "date"
- "trailer" "transfer-encoding" "upgrade" "via" "warning"
- "content-language" "content-length" "content-location"
- "content-md5" "content-range" "content-type" "etag" "expires"
- "last-modified" "set-cookie"
- "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday" "Sunday"
- "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"
- "chunked" "text/html" "image/png" "image/jpg" "image/gif"
- "application/xml" "application/xhtml" "text/plain" "public" "max-age"
- "charset=iso-8859-1" "utf-8" "gzip" "deflate" "HTTP/1.1" "status"
- "version" "url";
+static const u_char ngx_http_spdy_dict[] = {
+ 0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69, /* - - - - o p t i */
+ 0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68, /* o n s - - - - h */
+ 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70, /* e a d - - - - p */
+ 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70, /* o s t - - - - p */
+ 0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65, /* u t - - - - d e */
+ 0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05, /* l e t e - - - - */
+ 0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00, /* t r a c e - - - */
+ 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00, /* - a c c e p t - */
+ 0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, /* - - - a c c e p */
+ 0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, /* t - c h a r s e */
+ 0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63, /* t - - - - a c c */
+ 0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, /* e p t - e n c o */
+ 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f, /* d i n g - - - - */
+ 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c, /* a c c e p t - l */
+ 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, /* a n g u a g e - */
+ 0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, /* - - - a c c e p */
+ 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, /* t - r a n g e s */
+ 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00, /* - - - - a g e - */
+ 0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, /* - - - a l l o w */
+ 0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68, /* - - - - a u t h */
+ 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, /* o r i z a t i o */
+ 0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63, /* n - - - - c a c */
+ 0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, /* h e - c o n t r */
+ 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, /* o l - - - - c o */
+ 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, /* n n e c t i o n */
+ 0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, /* - - - - c o n t */
+ 0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65, /* e n t - b a s e */
+ 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74, /* - - - - c o n t */
+ 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, /* e n t - e n c o */
+ 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, /* d i n g - - - - */
+ 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, /* c o n t e n t - */
+ 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, /* l a n g u a g e */
+ 0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74, /* - - - - c o n t */
+ 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67, /* e n t - l e n g */
+ 0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, /* t h - - - - c o */
+ 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f, /* n t e n t - l o */
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, /* c a t i o n - - */
+ 0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, /* - - c o n t e n */
+ 0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00, /* t - m d 5 - - - */
+ 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, /* - c o n t e n t */
+ 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, /* - r a n g e - - */
+ 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, /* - - c o n t e n */
+ 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00, /* t - t y p e - - */
+ 0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00, /* - - d a t e - - */
+ 0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00, /* - - e t a g - - */
+ 0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, /* - - e x p e c t */
+ 0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69, /* - - - - e x p i */
+ 0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66, /* r e s - - - - f */
+ 0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68, /* r o m - - - - h */
+ 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69, /* o s t - - - - i */
+ 0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, /* f - m a t c h - */
+ 0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f, /* - - - i f - m o */
+ 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73, /* d i f i e d - s */
+ 0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d, /* i n c e - - - - */
+ 0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d, /* i f - n o n e - */
+ 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00, /* m a t c h - - - */
+ 0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67, /* - i f - r a n g */
+ 0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d, /* e - - - - i f - */
+ 0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, /* u n m o d i f i */
+ 0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65, /* e d - s i n c e */
+ 0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74, /* - - - - l a s t */
+ 0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, /* - m o d i f i e */
+ 0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63, /* d - - - - l o c */
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, /* a t i o n - - - */
+ 0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72, /* - m a x - f o r */
+ 0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00, /* w a r d s - - - */
+ 0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00, /* - p r a g m a - */
+ 0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79, /* - - - p r o x y */
+ 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, /* - a u t h e n t */
+ 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, /* i c a t e - - - */
+ 0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61, /* - p r o x y - a */
+ 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, /* u t h o r i z a */
+ 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05, /* t i o n - - - - */
+ 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00, /* r a n g e - - - */
+ 0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, /* - r e f e r e r */
+ 0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72, /* - - - - r e t r */
+ 0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00, /* y - a f t e r - */
+ 0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, /* - - - s e r v e */
+ 0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00, /* r - - - - t e - */
+ 0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c, /* - - - t r a i l */
+ 0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72, /* e r - - - - t r */
+ 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65, /* a n s f e r - e */
+ 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00, /* n c o d i n g - */
+ 0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61, /* - - - u p g r a */
+ 0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73, /* d e - - - - u s */
+ 0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, /* e r - a g e n t */
+ 0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79, /* - - - - v a r y */
+ 0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00, /* - - - - v i a - */
+ 0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69, /* - - - w a r n i */
+ 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77, /* n g - - - - w w */
+ 0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, /* w - a u t h e n */
+ 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, /* t i c a t e - - */
+ 0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, /* - - m e t h o d */
+ 0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00, /* - - - - g e t - */
+ 0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, /* - - - s t a t u */
+ 0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30, /* s - - - - 2 0 0 */
+ 0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76, /* - O K - - - - v */
+ 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00, /* e r s i o n - - */
+ 0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, /* - - H T T P - 1 */
+ 0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72, /* - 1 - - - - u r */
+ 0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62, /* l - - - - p u b */
+ 0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73, /* l i c - - - - s */
+ 0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69, /* e t - c o o k i */
+ 0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65, /* e - - - - k e e */
+ 0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00, /* p - a l i v e - */
+ 0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, /* - - - o r i g i */
+ 0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32, /* n 1 0 0 1 0 1 2 */
+ 0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35, /* 0 1 2 0 2 2 0 5 */
+ 0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30, /* 2 0 6 3 0 0 3 0 */
+ 0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33, /* 2 3 0 3 3 0 4 3 */
+ 0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37, /* 0 5 3 0 6 3 0 7 */
+ 0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30, /* 4 0 2 4 0 5 4 0 */
+ 0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34, /* 6 4 0 7 4 0 8 4 */
+ 0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31, /* 0 9 4 1 0 4 1 1 */
+ 0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31, /* 4 1 2 4 1 3 4 1 */
+ 0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34, /* 4 4 1 5 4 1 6 4 */
+ 0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34, /* 1 7 5 0 2 5 0 4 */
+ 0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e, /* 5 0 5 2 0 3 - N */
+ 0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f, /* o n - A u t h o */
+ 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, /* r i t a t i v e */
+ 0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, /* - I n f o r m a */
+ 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20, /* t i o n 2 0 4 - */
+ 0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, /* N o - C o n t e */
+ 0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f, /* n t 3 0 1 - M o */
+ 0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d, /* v e d - P e r m */
+ 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34, /* a n e n t l y 4 */
+ 0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52, /* 0 0 - B a d - R */
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30, /* e q u e s t 4 0 */
+ 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, /* 1 - U n a u t h */
+ 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30, /* o r i z e d 4 0 */
+ 0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, /* 3 - F o r b i d */
+ 0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e, /* d e n 4 0 4 - N */
+ 0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, /* o t - F o u n d */
+ 0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65, /* 5 0 0 - I n t e */
+ 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, /* r n a l - S e r */
+ 0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f, /* v e r - E r r o */
+ 0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74, /* r 5 0 1 - N o t */
+ 0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, /* - I m p l e m e */
+ 0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20, /* n t e d 5 0 3 - */
+ 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, /* S e r v i c e - */
+ 0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, /* U n a v a i l a */
+ 0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46, /* b l e J a n - F */
+ 0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41, /* e b - M a r - A */
+ 0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a, /* p r - M a y - J */
+ 0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41, /* u n - J u l - A */
+ 0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20, /* u g - S e p t - */
+ 0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20, /* O c t - N o v - */
+ 0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30, /* D e c - 0 0 - 0 */
+ 0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e, /* 0 - 0 0 - M o n */
+ 0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57, /* - - T u e - - W */
+ 0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c, /* e d - - T h u - */
+ 0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61, /* - F r i - - S a */
+ 0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20, /* t - - S u n - - */
+ 0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b, /* G M T c h u n k */
+ 0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, /* e d - t e x t - */
+ 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61, /* h t m l - i m a */
+ 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69, /* g e - p n g - i */
+ 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67, /* m a g e - j p g */
+ 0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, /* - i m a g e - g */
+ 0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, /* i f - a p p l i */
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, /* c a t i o n - x */
+ 0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, /* m l - a p p l i */
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, /* c a t i o n - x */
+ 0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, /* h t m l - x m l */
+ 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, /* - t e x t - p l */
+ 0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74, /* a i n - t e x t */
+ 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, /* - j a v a s c r */
+ 0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c, /* i p t - p u b l */
+ 0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, /* i c p r i v a t */
+ 0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65, /* e m a x - a g e */
+ 0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65, /* - g z i p - d e */
+ 0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64, /* f l a t e - s d */
+ 0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, /* c h c h a r s e */
+ 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63, /* t - u t f - 8 c */
+ 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69, /* h a r s e t - i */
+ 0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d, /* s o - 8 8 5 9 - */
+ 0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a, /* 1 - u t f - - - */
+ 0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e /* - e n q - 0 - */
+};
static ngx_http_spdy_request_header_t ngx_http_spdy_request_headers[] = {
{ 0, 6, "method", ngx_http_spdy_parse_method },
{ 0, 6, "scheme", ngx_http_spdy_parse_scheme },
- { 0, 3, "url", ngx_http_spdy_parse_url },
+ { 0, 4, "host", ngx_http_spdy_parse_host },
+ { 0, 4, "path", ngx_http_spdy_parse_path },
{ 0, 7, "version", ngx_http_spdy_parse_version },
};
@@ -233,7 +416,17 @@ ngx_http_spdy_init(ngx_event_t *rev)
sc->connection = c;
sc->http_connection = hc;
- sc->handler = ngx_http_spdy_state_detect_settings;
+ sc->send_window = NGX_SPDY_CONNECTION_WINDOW;
+ sc->recv_window = NGX_SPDY_CONNECTION_WINDOW;
+
+ sc->init_window = NGX_SPDY_INIT_STREAM_WINDOW;
+
+ sc->handler = ngx_http_spdy_state_head;
+
+ if (hc->proxy_protocol) {
+ c->log->action = "reading PROXY protocol";
+ sc->handler = ngx_http_spdy_proxy_protocol;
+ }
sc->zstream_in.zalloc = ngx_http_spdy_zalloc;
sc->zstream_in.zfree = ngx_http_spdy_zfree;
@@ -295,6 +488,24 @@ ngx_http_spdy_init(ngx_event_t *rev)
return;
}
+ if (ngx_http_spdy_send_settings(sc) == NGX_ERROR) {
+ ngx_http_close_connection(c);
+ return;
+ }
+
+ if (ngx_http_spdy_send_window_update(sc, 0, NGX_SPDY_MAX_WINDOW
+ - sc->recv_window)
+ == NGX_ERROR)
+ {
+ ngx_http_close_connection(c);
+ return;
+ }
+
+ sc->recv_window = NGX_SPDY_MAX_WINDOW;
+
+ ngx_queue_init(&sc->waiting);
+ ngx_queue_init(&sc->posted);
+
c->data = sc;
rev->handler = ngx_http_spdy_read_handler;
@@ -344,7 +555,7 @@ ngx_http_spdy_read_handler(ngx_event_t *rev)
break;
}
- if (n == 0 && (sc->waiting || sc->processing)) {
+ if (n == 0 && (sc->incomplete || sc->processing)) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"client closed prematurely connection");
}
@@ -358,7 +569,7 @@ ngx_http_spdy_read_handler(ngx_event_t *rev)
end += n;
sc->buffer_used = 0;
- sc->waiting = 0;
+ sc->incomplete = 0;
do {
p = sc->handler(sc, p, end);
@@ -376,6 +587,11 @@ ngx_http_spdy_read_handler(ngx_event_t *rev)
return;
}
+ if (sc->last_out && ngx_http_spdy_send_output_queue(sc) == NGX_ERROR) {
+ ngx_http_spdy_finalize_connection(sc, NGX_HTTP_CLIENT_CLOSED_REQUEST);
+ return;
+ }
+
sc->blocked = 0;
if (sc->processing) {
@@ -393,8 +609,9 @@ static void
ngx_http_spdy_write_handler(ngx_event_t *wev)
{
ngx_int_t rc;
+ ngx_queue_t *q;
ngx_connection_t *c;
- ngx_http_spdy_stream_t *stream, *s, *sn;
+ ngx_http_spdy_stream_t *stream;
ngx_http_spdy_connection_t *sc;
c = wev->data;
@@ -409,7 +626,7 @@ ngx_http_spdy_write_handler(ngx_event_t *wev)
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "spdy write handler");
- sc->blocked = 2;
+ sc->blocked = 1;
rc = ngx_http_spdy_send_output_queue(sc);
@@ -418,20 +635,13 @@ ngx_http_spdy_write_handler(ngx_event_t *wev)
return;
}
- stream = NULL;
+ while (!ngx_queue_empty(&sc->posted)) {
+ q = ngx_queue_head(&sc->posted);
- for (s = sc->last_stream; s; s = sn) {
- sn = s->next;
- s->next = stream;
- stream = s;
- }
+ ngx_queue_remove(q);
- sc->last_stream = NULL;
+ stream = ngx_queue_data(q, ngx_http_spdy_stream_t, queue);
- sc->blocked = 1;
-
- for ( /* void */ ; stream; stream = sn) {
- sn = stream->next;
stream->handled = 0;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
@@ -484,9 +694,9 @@ ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc)
out = frame;
ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0,
- "spdy frame out: %p sid:%ui prio:%ui bl:%ui size:%uz",
+ "spdy frame out: %p sid:%ui prio:%ui bl:%d len:%uz",
out, out->stream ? out->stream->id : 0, out->priority,
- out->blocked, out->size);
+ out->blocked, out->length);
}
cl = c->send_chain(c, cl, 0);
@@ -517,7 +727,9 @@ ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc)
}
}
- for ( /* void */ ; out; out = out->next) {
+ for ( /* void */ ; out; out = fn) {
+ fn = out->next;
+
if (out->handler(sc, out) != NGX_OK) {
out->blocked = 1;
out->priority = NGX_SPDY_HIGHEST_PRIORITY;
@@ -525,9 +737,9 @@ ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc)
}
ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0,
- "spdy frame sent: %p sid:%ui bl:%ui size:%uz",
+ "spdy frame sent: %p sid:%ui bl:%d len:%uz",
out, out->stream ? out->stream->id : 0,
- out->blocked, out->size);
+ out->blocked, out->length);
}
frame = NULL;
@@ -567,7 +779,7 @@ ngx_http_spdy_handle_connection(ngx_http_spdy_connection_t *sc)
sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
ngx_http_spdy_module);
- if (sc->waiting) {
+ if (sc->incomplete) {
ngx_add_timer(c->read, sscf->recv_timeout);
return;
}
@@ -605,34 +817,18 @@ ngx_http_spdy_handle_connection(ngx_http_spdy_connection_t *sc)
static u_char *
-ngx_http_spdy_state_detect_settings(ngx_http_spdy_connection_t *sc,
- u_char *pos, u_char *end)
+ngx_http_spdy_proxy_protocol(ngx_http_spdy_connection_t *sc, u_char *pos,
+ u_char *end)
{
- if (end - pos < NGX_SPDY_FRAME_HEADER_SIZE) {
- return ngx_http_spdy_state_save(sc, pos, end,
- ngx_http_spdy_state_detect_settings);
- }
-
- /*
- * Since this is the first frame in a buffer,
- * then it is properly aligned
- */
-
- if (*(uint32_t *) pos == htonl(ngx_spdy_ctl_frame_head(NGX_SPDY_SETTINGS)))
- {
- sc->length = ngx_spdy_frame_length(htonl(((uint32_t *) pos)[1]));
-
- ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
- "spdy SETTINGS frame received, size: %uz", sc->length);
-
- pos += NGX_SPDY_FRAME_HEADER_SIZE;
+ pos = ngx_proxy_protocol_parse(sc->connection, pos, end);
- return ngx_http_spdy_state_settings(sc, pos, end);
+ if (pos == NULL) {
+ return ngx_http_spdy_state_protocol_error(sc);
}
- ngx_http_spdy_send_settings(sc);
+ sc->connection->log->action = "processing SPDY";
- return ngx_http_spdy_state_head(sc, pos, end);
+ return ngx_http_spdy_state_complete(sc, pos, end);
}
@@ -640,7 +836,8 @@ static u_char *
ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos,
u_char *end)
{
- uint32_t head, flen;
+ uint32_t head, flen;
+ ngx_uint_t type;
if (end - pos < NGX_SPDY_FRAME_HEADER_SIZE) {
return ngx_http_spdy_state_save(sc, pos, end,
@@ -659,11 +856,13 @@ ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos,
pos += sizeof(uint32_t);
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
- "spdy process frame head:%08Xd f:%ui l:%ui",
+ "spdy process frame head:%08XD f:%Xd l:%uz",
head, sc->flags, sc->length);
if (ngx_spdy_ctl_frame_check(head)) {
- switch (ngx_spdy_ctl_frame_type(head)) {
+ type = ngx_spdy_ctl_frame_type(head);
+
+ switch (type) {
case NGX_SPDY_SYN_STREAM:
return ngx_http_spdy_state_syn_stream(sc, pos, end);
@@ -675,10 +874,7 @@ ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos,
return ngx_http_spdy_state_rst_stream(sc, pos, end);
case NGX_SPDY_SETTINGS:
- return ngx_http_spdy_state_skip(sc, pos, end);
-
- case NGX_SPDY_NOOP:
- return ngx_http_spdy_state_noop(sc, pos, end);
+ return ngx_http_spdy_state_settings(sc, pos, end);
case NGX_SPDY_PING:
return ngx_http_spdy_state_ping(sc, pos, end);
@@ -689,7 +885,12 @@ ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos,
case NGX_SPDY_HEADERS:
return ngx_http_spdy_state_protocol_error(sc);
- default: /* TODO logging */
+ case NGX_SPDY_WINDOW_UPDATE:
+ return ngx_http_spdy_state_window_update(sc, pos, end);
+
+ default:
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
+ "spdy control frame with unknown type %ui", type);
return ngx_http_spdy_state_skip(sc, pos, end);
}
}
@@ -729,7 +930,7 @@ ngx_http_spdy_state_syn_stream(ngx_http_spdy_connection_t *sc, u_char *pos,
sc->length -= NGX_SPDY_SYN_STREAM_SIZE;
sid = ngx_spdy_frame_parse_sid(pos);
- prio = pos[8] >> 6;
+ prio = pos[8] >> 5;
pos += NGX_SPDY_SYN_STREAM_SIZE;
@@ -742,7 +943,7 @@ ngx_http_spdy_state_syn_stream(ngx_http_spdy_connection_t *sc, u_char *pos,
if (sc->processing >= sscf->concurrent_streams) {
ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
- "spdy concurrent streams excessed %ui", sc->processing);
+ "spdy concurrent streams exceeded %ui", sc->processing);
if (ngx_http_spdy_send_rst_stream(sc, sid, NGX_SPDY_REFUSED_STREAM,
prio)
@@ -809,6 +1010,8 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
sc->zstream_in.next_in = pos;
sc->zstream_in.avail_in = size;
sc->zstream_in.next_out = buf->last;
+
+ /* one byte is reserved for null-termination of the last header value */
sc->zstream_in.avail_out = buf->end - buf->last - 1;
z = inflate(&sc->zstream_in, Z_NO_FLUSH);
@@ -851,18 +1054,28 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
if (r->headers_in.headers.part.elts == NULL) {
if (buf->last - buf->pos < NGX_SPDY_NV_NUM_SIZE) {
+
+ if (complete) {
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent SYN_STREAM frame "
+ "with invalid HEADERS block");
+ ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST);
+ return ngx_http_spdy_state_protocol_error(sc);
+ }
+
return ngx_http_spdy_state_save(sc, pos, end,
ngx_http_spdy_state_headers);
}
- sc->headers = ngx_spdy_frame_parse_uint16(buf->pos);
+ sc->entries = ngx_spdy_frame_parse_uint32(buf->pos);
buf->pos += NGX_SPDY_NV_NUM_SIZE;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "spdy headers count: %ui", sc->headers);
+ "spdy HEADERS block consists of %ui entries",
+ sc->entries);
- if (ngx_list_init(&r->headers_in.headers, r->pool, sc->headers + 3,
+ if (ngx_list_init(&r->headers_in.headers, r->pool, 20,
sizeof(ngx_table_elt_t))
!= NGX_OK)
{
@@ -881,14 +1094,14 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
}
}
- while (sc->headers) {
+ while (sc->entries) {
rc = ngx_http_spdy_parse_header(r);
switch (rc) {
case NGX_DONE:
- sc->headers--;
+ sc->entries--;
case NGX_OK:
break;
@@ -912,9 +1125,14 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
return ngx_http_spdy_state_headers_error(sc, pos, end);
}
+ /* null-terminate the last processed header name or value */
+ *buf->pos = '\0';
+
buf = r->header_in;
sc->zstream_in.next_out = buf->last;
+
+ /* one byte is reserved for null-termination */
sc->zstream_in.avail_out = buf->end - buf->last - 1;
z = inflate(&sc->zstream_in, Z_NO_FLUSH);
@@ -983,10 +1201,10 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
}
}
- if (buf->pos != buf->last) {
- /* TODO: improve error message */
- ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "end %ui %p %p", complete, buf->pos, buf->last);
+ if (buf->pos != buf->last || sc->zstream_in.avail_in) {
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent SYN_STREAM frame "
+ "with invalid HEADERS block");
ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST);
return ngx_http_spdy_state_protocol_error(sc);
}
@@ -996,6 +1214,9 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
ngx_http_spdy_state_headers);
}
+ /* null-terminate the last header value */
+ *buf->pos = '\0';
+
ngx_http_spdy_run_request(r);
return ngx_http_spdy_state_complete(sc, pos, end);
@@ -1064,14 +1285,224 @@ ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc, u_char *pos,
static u_char *
+ngx_http_spdy_state_window_update(ngx_http_spdy_connection_t *sc, u_char *pos,
+ u_char *end)
+{
+ size_t delta;
+ ngx_uint_t sid;
+ ngx_event_t *wev;
+ ngx_queue_t *q;
+ ngx_http_spdy_stream_t *stream;
+
+ if (end - pos < NGX_SPDY_WINDOW_UPDATE_SIZE) {
+ return ngx_http_spdy_state_save(sc, pos, end,
+ ngx_http_spdy_state_window_update);
+ }
+
+ if (sc->length != NGX_SPDY_WINDOW_UPDATE_SIZE) {
+ ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
+ "client sent WINDOW_UPDATE frame "
+ "with incorrect length %uz", sc->length);
+
+ return ngx_http_spdy_state_protocol_error(sc);
+ }
+
+ sid = ngx_spdy_frame_parse_sid(pos);
+
+ pos += NGX_SPDY_SID_SIZE;
+
+ delta = ngx_spdy_frame_parse_delta(pos);
+
+ pos += NGX_SPDY_DELTA_SIZE;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
+ "spdy WINDOW_UPDATE sid:%ui delta:%ui", sid, delta);
+
+ if (sid) {
+ stream = ngx_http_spdy_get_stream_by_id(sc, sid);
+
+ if (stream == NULL) {
+ ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
+ "client sent WINDOW_UPDATE frame "
+ "for unknown stream %ui", sid);
+
+ if (ngx_http_spdy_send_rst_stream(sc, sid, NGX_SPDY_INVALID_STREAM,
+ NGX_SPDY_LOWEST_PRIORITY)
+ == NGX_ERROR)
+ {
+ return ngx_http_spdy_state_internal_error(sc);
+ }
+
+ return ngx_http_spdy_state_complete(sc, pos, end);
+ }
+
+ if (stream->send_window > (ssize_t) (NGX_SPDY_MAX_WINDOW - delta)) {
+
+ ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
+ "client violated flow control for stream %ui: "
+ "received WINDOW_UPDATE frame with delta %uz "
+ "that is not allowed for window %z",
+ sid, delta, stream->send_window);
+
+ if (ngx_http_spdy_terminate_stream(sc, stream,
+ NGX_SPDY_FLOW_CONTROL_ERROR)
+ == NGX_ERROR)
+ {
+ return ngx_http_spdy_state_internal_error(sc);
+ }
+
+ return ngx_http_spdy_state_complete(sc, pos, end);
+ }
+
+ stream->send_window += delta;
+
+ if (stream->exhausted) {
+ stream->exhausted = 0;
+
+ wev = stream->request->connection->write;
+
+ if (!wev->timer_set) {
+ wev->delayed = 0;
+ wev->handler(wev);
+ }
+ }
+
+ } else {
+ sc->send_window += delta;
+
+ if (sc->send_window > NGX_SPDY_MAX_WINDOW) {
+ ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
+ "client violated connection flow control: "
+ "received WINDOW_UPDATE frame with delta %uz "
+ "that is not allowed for window %uz",
+ delta, sc->send_window);
+
+ return ngx_http_spdy_state_protocol_error(sc);
+ }
+
+ while (!ngx_queue_empty(&sc->waiting)) {
+ q = ngx_queue_head(&sc->waiting);
+
+ ngx_queue_remove(q);
+
+ stream = ngx_queue_data(q, ngx_http_spdy_stream_t, queue);
+
+ stream->handled = 0;
+
+ wev = stream->request->connection->write;
+
+ if (!wev->timer_set) {
+ wev->delayed = 0;
+ wev->handler(wev);
+
+ if (sc->send_window == 0) {
+ break;
+ }
+ }
+ }
+ }
+
+ return ngx_http_spdy_state_complete(sc, pos, end);
+}
+
+
+static u_char *
ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc, u_char *pos,
u_char *end)
{
+ ngx_http_spdy_stream_t *stream;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
+ "spdy DATA frame");
+
+ if (sc->length > sc->recv_window) {
+ ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
+ "client violated connection flow control: length of "
+ "received DATA frame %uz, while available window %uz",
+ sc->length, sc->recv_window);
+
+ return ngx_http_spdy_state_protocol_error(sc);
+ }
+
+ sc->recv_window -= sc->length;
+
+ if (sc->recv_window < NGX_SPDY_MAX_WINDOW / 4) {
+
+ if (ngx_http_spdy_send_window_update(sc, 0,
+ NGX_SPDY_MAX_WINDOW
+ - sc->recv_window)
+ == NGX_ERROR)
+ {
+ return ngx_http_spdy_state_internal_error(sc);
+ }
+
+ sc->recv_window = NGX_SPDY_MAX_WINDOW;
+ }
+
+ stream = sc->stream;
+
+ if (stream == NULL) {
+ return ngx_http_spdy_state_skip(sc, pos, end);
+ }
+
+ if (sc->length > stream->recv_window) {
+ ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
+ "client violated flow control for stream %ui: length of "
+ "received DATA frame %uz, while available window %uz",
+ stream->id, sc->length, stream->recv_window);
+
+ if (ngx_http_spdy_terminate_stream(sc, stream,
+ NGX_SPDY_FLOW_CONTROL_ERROR)
+ == NGX_ERROR)
+ {
+ return ngx_http_spdy_state_internal_error(sc);
+ }
+
+ return ngx_http_spdy_state_skip(sc, pos, end);
+ }
+
+ stream->recv_window -= sc->length;
+
+ if (stream->recv_window < NGX_SPDY_STREAM_WINDOW / 4) {
+
+ if (ngx_http_spdy_send_window_update(sc, stream->id,
+ NGX_SPDY_STREAM_WINDOW
+ - stream->recv_window)
+ == NGX_ERROR)
+ {
+ return ngx_http_spdy_state_internal_error(sc);
+ }
+
+ stream->recv_window = NGX_SPDY_STREAM_WINDOW;
+ }
+
+ if (stream->in_closed) {
+ ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
+ "client sent DATA frame for half closed stream %ui",
+ stream->id);
+
+ if (ngx_http_spdy_terminate_stream(sc, stream,
+ NGX_SPDY_STREAM_ALREADY_CLOSED)
+ == NGX_ERROR)
+ {
+ return ngx_http_spdy_state_internal_error(sc);
+ }
+
+ return ngx_http_spdy_state_skip(sc, pos, end);
+ }
+
+ return ngx_http_spdy_state_read_data(sc, pos, end);
+}
+
+
+static u_char *
+ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, u_char *pos,
+ u_char *end)
+{
size_t size;
ssize_t n;
ngx_buf_t *buf;
ngx_int_t rc;
- ngx_uint_t complete;
ngx_temp_file_t *tf;
ngx_http_request_t *r;
ngx_http_spdy_stream_t *stream;
@@ -1080,18 +1511,10 @@ ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc, u_char *pos,
stream = sc->stream;
- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
- "spdy DATA frame");
-
if (stream == NULL) {
return ngx_http_spdy_state_skip(sc, pos, end);
}
- if (stream->in_closed) {
- /* TODO log */
- return ngx_http_spdy_state_protocol_error(sc);
- }
-
if (stream->skip_data) {
if (sc->flags & NGX_SPDY_FLAG_FIN) {
@@ -1104,13 +1527,8 @@ ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc, u_char *pos,
size = end - pos;
- if (size >= sc->length) {
+ if (size > sc->length) {
size = sc->length;
- complete = 1;
-
- } else {
- sc->length -= size;
- complete = 0;
}
r = stream->request;
@@ -1152,6 +1570,8 @@ ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc, u_char *pos,
}
}
+ sc->length -= size;
+
if (tf) {
buf->start = pos;
buf->pos = pos;
@@ -1180,15 +1600,28 @@ ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc, u_char *pos,
r->request_length += size;
}
- if (!complete) {
+ if (sc->length) {
return ngx_http_spdy_state_save(sc, pos, end,
- ngx_http_spdy_state_data);
+ ngx_http_spdy_state_read_data);
}
if (sc->flags & NGX_SPDY_FLAG_FIN) {
stream->in_closed = 1;
+ if (r->headers_in.content_length_n < 0) {
+ r->headers_in.content_length_n = rb->rest;
+
+ } else if (r->headers_in.content_length_n != rb->rest) {
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client prematurely closed stream: "
+ "%O of %O bytes of request body received",
+ rb->rest, r->headers_in.content_length_n);
+
+ stream->skip_data = NGX_SPDY_DATA_ERROR;
+ goto error;
+ }
+
if (tf) {
ngx_memzero(buf, sizeof(ngx_buf_t));
@@ -1199,11 +1632,8 @@ ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc, u_char *pos,
rb->buf = NULL;
}
- if (r->headers_in.content_length_n < 0) {
- r->headers_in.content_length_n = rb->rest;
- }
-
if (rb->post_handler) {
+ r->read_event_handler = ngx_http_block_reading;
rb->post_handler(r);
}
}
@@ -1237,7 +1667,6 @@ ngx_http_spdy_state_rst_stream(ngx_http_spdy_connection_t *sc, u_char *pos,
ngx_uint_t sid, status;
ngx_event_t *ev;
ngx_connection_t *fc;
- ngx_http_request_t *r;
ngx_http_spdy_stream_t *stream;
if (end - pos < NGX_SPDY_RST_STREAM_SIZE) {
@@ -1246,7 +1675,10 @@ ngx_http_spdy_state_rst_stream(ngx_http_spdy_connection_t *sc, u_char *pos,
}
if (sc->length != NGX_SPDY_RST_STREAM_SIZE) {
- /* TODO logging */
+ ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
+ "client sent RST_STREAM frame with incorrect length %uz",
+ sc->length);
+
return ngx_http_spdy_state_protocol_error(sc);
}
@@ -1261,55 +1693,42 @@ ngx_http_spdy_state_rst_stream(ngx_http_spdy_connection_t *sc, u_char *pos,
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
"spdy RST_STREAM sid:%ui st:%ui", sid, status);
+ stream = ngx_http_spdy_get_stream_by_id(sc, sid);
+ if (stream == NULL) {
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
+ "unknown stream, probably it has been closed already");
+ return ngx_http_spdy_state_complete(sc, pos, end);
+ }
- switch (status) {
+ stream->in_closed = 1;
+ stream->out_closed = 1;
- case NGX_SPDY_PROTOCOL_ERROR:
- /* TODO logging */
- return ngx_http_spdy_state_protocol_error(sc);
+ fc = stream->request->connection;
+ fc->error = 1;
- case NGX_SPDY_INVALID_STREAM:
- /* TODO */
- break;
+ switch (status) {
- case NGX_SPDY_REFUSED_STREAM:
- /* TODO */
+ case NGX_SPDY_CANCEL:
+ ngx_log_error(NGX_LOG_INFO, fc->log, 0,
+ "client canceled stream %ui", sid);
break;
- case NGX_SPDY_UNSUPPORTED_VERSION:
- /* TODO logging */
- return ngx_http_spdy_state_protocol_error(sc);
-
- case NGX_SPDY_CANCEL:
case NGX_SPDY_INTERNAL_ERROR:
- stream = ngx_http_spdy_get_stream_by_id(sc, sid);
- if (stream == NULL) {
- /* TODO false cancel */
- break;
- }
-
- stream->in_closed = 1;
- stream->out_closed = 1;
-
- r = stream->request;
-
- fc = r->connection;
- fc->error = 1;
-
- ev = fc->read;
- ev->handler(ev);
-
+ ngx_log_error(NGX_LOG_INFO, fc->log, 0,
+ "client terminated stream %ui because of internal error",
+ sid);
break;
- case NGX_SPDY_FLOW_CONTROL_ERROR:
- /* TODO logging */
- return ngx_http_spdy_state_protocol_error(sc);
-
default:
- /* TODO */
- return ngx_http_spdy_state_protocol_error(sc);
+ ngx_log_error(NGX_LOG_INFO, fc->log, 0,
+ "client terminated stream %ui with status %ui",
+ sid, status);
+ break;
}
+ ev = fc->read;
+ ev->handler(ev);
+
return ngx_http_spdy_state_complete(sc, pos, end);
}
@@ -1382,70 +1801,77 @@ static u_char *
ngx_http_spdy_state_settings(ngx_http_spdy_connection_t *sc, u_char *pos,
u_char *end)
{
- ngx_uint_t v;
- ngx_http_spdy_srv_conf_t *sscf;
+ ngx_uint_t fid, val;
- if (sc->headers == 0) {
+ if (sc->entries == 0) {
if (end - pos < NGX_SPDY_SETTINGS_NUM_SIZE) {
return ngx_http_spdy_state_save(sc, pos, end,
ngx_http_spdy_state_settings);
}
- sc->headers = ngx_spdy_frame_parse_uint32(pos);
+ sc->entries = ngx_spdy_frame_parse_uint32(pos);
pos += NGX_SPDY_SETTINGS_NUM_SIZE;
sc->length -= NGX_SPDY_SETTINGS_NUM_SIZE;
- if (sc->length < sc->headers * NGX_SPDY_SETTINGS_PAIR_SIZE) {
+ if (sc->length < sc->entries * NGX_SPDY_SETTINGS_PAIR_SIZE) {
/* TODO logging */
return ngx_http_spdy_state_protocol_error(sc);
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
"spdy SETTINGS frame consists of %ui entries",
- sc->headers);
+ sc->entries);
}
- while (sc->headers) {
+ while (sc->entries) {
if (end - pos < NGX_SPDY_SETTINGS_PAIR_SIZE) {
return ngx_http_spdy_state_save(sc, pos, end,
ngx_http_spdy_state_settings);
}
- sc->headers--;
+ sc->entries--;
+ sc->length -= NGX_SPDY_SETTINGS_PAIR_SIZE;
- if (pos[0] != NGX_SPDY_SETTINGS_MAX_STREAMS) {
- pos += NGX_SPDY_SETTINGS_PAIR_SIZE;
- sc->length -= NGX_SPDY_SETTINGS_PAIR_SIZE;
- continue;
- }
+ fid = ngx_spdy_frame_parse_uint32(pos);
+
+ pos += NGX_SPDY_SETTINGS_FID_SIZE;
+
+ val = ngx_spdy_frame_parse_uint32(pos);
- v = ngx_spdy_frame_parse_uint32(pos + NGX_SPDY_SETTINGS_IDF_SIZE);
+ pos += NGX_SPDY_SETTINGS_VAL_SIZE;
- sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
- ngx_http_spdy_module);
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
+ "spdy SETTINGS entry fl:%ui id:%ui val:%ui",
+ ngx_spdy_frame_flags(fid), ngx_spdy_frame_id(fid), val);
- if (v != sscf->concurrent_streams) {
- ngx_http_spdy_send_settings(sc);
+ if (ngx_spdy_frame_flags(fid) == NGX_SPDY_SETTINGS_FLAG_PERSISTED) {
+ continue;
}
- return ngx_http_spdy_state_skip(sc, pos, end);
- }
+ switch (ngx_spdy_frame_id(fid)) {
- ngx_http_spdy_send_settings(sc);
+ case NGX_SPDY_SETTINGS_INIT_WINDOW:
- return ngx_http_spdy_state_complete(sc, pos, end);
-}
+ if (val > NGX_SPDY_MAX_WINDOW) {
+ ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
+ "client sent SETTINGS frame with "
+ "incorrect INIT_WINDOW value: %ui", val);
+
+ return ngx_http_spdy_state_protocol_error(sc);
+ }
+ if (ngx_http_spdy_adjust_windows(sc, val - sc->init_window)
+ != NGX_OK)
+ {
+ return ngx_http_spdy_state_internal_error(sc);
+ }
-static u_char *
-ngx_http_spdy_state_noop(ngx_http_spdy_connection_t *sc, u_char *pos,
- u_char *end)
-{
- if (sc->length) {
- /* TODO logging */
- return ngx_http_spdy_state_protocol_error(sc);
+ sc->init_window = val;
+
+ continue;
+ }
}
return ngx_http_spdy_state_complete(sc, pos, end);
@@ -1465,20 +1891,22 @@ static u_char *
ngx_http_spdy_state_save(ngx_http_spdy_connection_t *sc,
u_char *pos, u_char *end, ngx_http_spdy_handler_pt handler)
{
-#if 1
- if (end - pos > NGX_SPDY_STATE_BUFFER_SIZE) {
+ size_t size;
+
+ size = end - pos;
+
+ if (size > NGX_SPDY_STATE_BUFFER_SIZE) {
ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0,
"spdy state buffer overflow: "
- "%i bytes required", end - pos);
+ "%uz bytes required", size);
return ngx_http_spdy_state_internal_error(sc);
}
-#endif
ngx_memcpy(sc->buffer, pos, NGX_SPDY_STATE_BUFFER_SIZE);
- sc->buffer_used = end - pos;
+ sc->buffer_used = size;
sc->handler = handler;
- sc->waiting = 1;
+ sc->incomplete = 1;
return end;
}
@@ -1509,6 +1937,41 @@ ngx_http_spdy_state_internal_error(ngx_http_spdy_connection_t *sc)
static ngx_int_t
+ngx_http_spdy_send_window_update(ngx_http_spdy_connection_t *sc, ngx_uint_t sid,
+ ngx_uint_t delta)
+{
+ u_char *p;
+ ngx_buf_t *buf;
+ ngx_http_spdy_out_frame_t *frame;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
+ "spdy write WINDOW_UPDATE sid:%ui delta:%ui", sid, delta);
+
+ frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_WINDOW_UPDATE_SIZE,
+ NGX_SPDY_HIGHEST_PRIORITY);
+ if (frame == NULL) {
+ return NGX_ERROR;
+ }
+
+ buf = frame->first->buf;
+
+ p = buf->pos;
+
+ p = ngx_spdy_frame_write_head(p, NGX_SPDY_WINDOW_UPDATE);
+ p = ngx_spdy_frame_write_flags_and_len(p, 0, NGX_SPDY_WINDOW_UPDATE_SIZE);
+
+ p = ngx_spdy_frame_write_sid(p, sid);
+ p = ngx_spdy_frame_aligned_write_uint32(p, delta);
+
+ buf->last = p;
+
+ ngx_http_spdy_queue_frame(sc, frame);
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
ngx_http_spdy_send_rst_stream(ngx_http_spdy_connection_t *sc, ngx_uint_t sid,
ngx_uint_t status, ngx_uint_t priority)
{
@@ -1587,7 +2050,6 @@ ngx_http_spdy_send_settings(ngx_http_spdy_connection_t *sc)
{
u_char *p;
ngx_buf_t *buf;
- ngx_pool_t *pool;
ngx_chain_t *cl;
ngx_http_spdy_srv_conf_t *sscf;
ngx_http_spdy_out_frame_t *frame;
@@ -1595,21 +2057,19 @@ ngx_http_spdy_send_settings(ngx_http_spdy_connection_t *sc)
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
"spdy create SETTINGS frame");
- pool = sc->connection->pool;
-
- frame = ngx_palloc(pool, sizeof(ngx_http_spdy_out_frame_t));
+ frame = ngx_palloc(sc->pool, sizeof(ngx_http_spdy_out_frame_t));
if (frame == NULL) {
return NGX_ERROR;
}
- cl = ngx_alloc_chain_link(pool);
+ cl = ngx_alloc_chain_link(sc->pool);
if (cl == NULL) {
return NGX_ERROR;
}
- buf = ngx_create_temp_buf(pool, NGX_SPDY_FRAME_HEADER_SIZE
- + NGX_SPDY_SETTINGS_NUM_SIZE
- + NGX_SPDY_SETTINGS_PAIR_SIZE);
+ buf = ngx_create_temp_buf(sc->pool, NGX_SPDY_FRAME_HEADER_SIZE
+ + NGX_SPDY_SETTINGS_NUM_SIZE
+ + 2 * NGX_SPDY_SETTINGS_PAIR_SIZE);
if (buf == NULL) {
return NGX_ERROR;
}
@@ -1622,11 +2082,10 @@ ngx_http_spdy_send_settings(ngx_http_spdy_connection_t *sc)
frame->first = cl;
frame->last = cl;
frame->handler = ngx_http_spdy_settings_frame_handler;
-#if (NGX_DEBUG)
frame->stream = NULL;
- frame->size = NGX_SPDY_FRAME_HEADER_SIZE
- + NGX_SPDY_SETTINGS_NUM_SIZE
- + NGX_SPDY_SETTINGS_PAIR_SIZE;
+#if (NGX_DEBUG)
+ frame->length = NGX_SPDY_SETTINGS_NUM_SIZE
+ + 2 * NGX_SPDY_SETTINGS_PAIR_SIZE;
#endif
frame->priority = NGX_SPDY_HIGHEST_PRIORITY;
frame->blocked = 0;
@@ -1635,19 +2094,20 @@ ngx_http_spdy_send_settings(ngx_http_spdy_connection_t *sc)
p = ngx_spdy_frame_write_head(p, NGX_SPDY_SETTINGS);
p = ngx_spdy_frame_write_flags_and_len(p, NGX_SPDY_FLAG_CLEAR_SETTINGS,
- NGX_SPDY_SETTINGS_NUM_SIZE
- + NGX_SPDY_SETTINGS_PAIR_SIZE);
+ NGX_SPDY_SETTINGS_NUM_SIZE
+ + 2 * NGX_SPDY_SETTINGS_PAIR_SIZE);
- p = ngx_spdy_frame_aligned_write_uint32(p, 1);
- p = ngx_spdy_frame_aligned_write_uint32(p,
- NGX_SPDY_SETTINGS_MAX_STREAMS << 24
- | NGX_SPDY_SETTINGS_FLAG_PERSIST);
+ p = ngx_spdy_frame_aligned_write_uint32(p, 2);
sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
ngx_http_spdy_module);
+ p = ngx_spdy_frame_write_flags_and_id(p, 0, NGX_SPDY_SETTINGS_MAX_STREAMS);
p = ngx_spdy_frame_aligned_write_uint32(p, sscf->concurrent_streams);
+ p = ngx_spdy_frame_write_flags_and_id(p, 0, NGX_SPDY_SETTINGS_INIT_WINDOW);
+ p = ngx_spdy_frame_aligned_write_uint32(p, NGX_SPDY_STREAM_WINDOW);
+
buf->last = p;
ngx_http_spdy_queue_frame(sc, frame);
@@ -1675,7 +2135,7 @@ ngx_http_spdy_settings_frame_handler(ngx_http_spdy_connection_t *sc,
static ngx_http_spdy_out_frame_t *
-ngx_http_spdy_get_ctl_frame(ngx_http_spdy_connection_t *sc, size_t size,
+ngx_http_spdy_get_ctl_frame(ngx_http_spdy_connection_t *sc, size_t length,
ngx_uint_t priority)
{
ngx_chain_t *cl;
@@ -1684,7 +2144,7 @@ ngx_http_spdy_get_ctl_frame(ngx_http_spdy_connection_t *sc, size_t size,
frame = sc->free_ctl_frames;
if (frame) {
- sc->free_ctl_frames = frame->free;
+ sc->free_ctl_frames = frame->next;
cl = frame->first;
cl->buf->pos = cl->buf->start;
@@ -1711,19 +2171,17 @@ ngx_http_spdy_get_ctl_frame(ngx_http_spdy_connection_t *sc, size_t size,
frame->first = cl;
frame->last = cl;
frame->handler = ngx_http_spdy_ctl_frame_handler;
+ frame->stream = NULL;
}
- frame->free = NULL;
-
#if (NGX_DEBUG)
- if (size > NGX_SPDY_CTL_FRAME_BUFFER_SIZE - NGX_SPDY_FRAME_HEADER_SIZE) {
+ if (length > NGX_SPDY_CTL_FRAME_BUFFER_SIZE - NGX_SPDY_FRAME_HEADER_SIZE) {
ngx_log_error(NGX_LOG_ALERT, sc->pool->log, 0,
- "requested control frame is too big: %z", size);
+ "requested control frame is too big: %uz", length);
return NULL;
}
- frame->stream = NULL;
- frame->size = size;
+ frame->length = length;
#endif
frame->priority = priority;
@@ -1745,7 +2203,7 @@ ngx_http_spdy_ctl_frame_handler(ngx_http_spdy_connection_t *sc,
return NGX_AGAIN;
}
- frame->free = sc->free_ctl_frames;
+ frame->next = sc->free_ctl_frames;
sc->free_ctl_frames = frame;
return NGX_OK;
@@ -1814,7 +2272,7 @@ ngx_http_spdy_create_stream(ngx_http_spdy_connection_t *sc, ngx_uint_t id,
rev->data = fc;
rev->ready = 1;
- rev->handler = ngx_http_empty_handler;
+ rev->handler = ngx_http_spdy_close_stream_handler;
rev->log = log;
ngx_memcpy(wev, rev, sizeof(ngx_event_t));
@@ -1864,6 +2322,10 @@ ngx_http_spdy_create_stream(ngx_http_spdy_connection_t *sc, ngx_uint_t id,
stream->id = id;
stream->request = r;
stream->connection = sc;
+
+ stream->send_window = sc->init_window;
+ stream->recv_window = NGX_SPDY_STREAM_WINDOW;
+
stream->priority = priority;
sscf = ngx_http_get_module_srv_conf(r, ngx_http_spdy_module);
@@ -1907,7 +2369,7 @@ static ngx_int_t
ngx_http_spdy_parse_header(ngx_http_request_t *r)
{
u_char *p, *end, ch;
- ngx_uint_t len, hash;
+ ngx_uint_t hash;
ngx_http_core_srv_conf_t *cscf;
enum {
@@ -1930,16 +2392,17 @@ ngx_http_spdy_parse_header(ngx_http_request_t *r)
return NGX_AGAIN;
}
- len = ngx_spdy_frame_parse_uint16(p);
+ r->lowcase_index = ngx_spdy_frame_parse_uint32(p);
- if (!len) {
+ if (r->lowcase_index == 0) {
return NGX_HTTP_PARSE_INVALID_HEADER;
}
+ /* null-terminate the previous header value */
+ *p = '\0';
+
p += NGX_SPDY_NV_NLEN_SIZE;
- r->header_name_end = p + len;
- r->lowcase_index = len;
r->invalid_header = 0;
state = sw_name;
@@ -1948,13 +2411,18 @@ ngx_http_spdy_parse_header(ngx_http_request_t *r)
case sw_name:
- if (r->header_name_end > end) {
+ if ((ngx_uint_t) (end - p) < r->lowcase_index) {
break;
}
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
r->header_name_start = p;
+ r->header_name_end = p + r->lowcase_index;
+
+ if (p[0] == ':') {
+ p++;
+ }
hash = 0;
@@ -1999,30 +2467,26 @@ ngx_http_spdy_parse_header(ngx_http_request_t *r)
break;
}
- len = ngx_spdy_frame_parse_uint16(p);
+ r->lowcase_index = ngx_spdy_frame_parse_uint32(p);
- if (!len) {
- return NGX_ERROR;
- }
+ /* null-terminate header name */
+ *p = '\0';
p += NGX_SPDY_NV_VLEN_SIZE;
- r->header_end = p + len;
-
state = sw_value;
/* fall through */
case sw_value:
- if (r->header_end > end) {
+ if ((ngx_uint_t) (end - p) < r->lowcase_index) {
break;
}
r->header_start = p;
- for ( /* void */ ; p != r->header_end; p++) {
-
+ while (r->lowcase_index--) {
ch = *p;
if (ch == '\0') {
@@ -2031,7 +2495,7 @@ ngx_http_spdy_parse_header(ngx_http_request_t *r)
return NGX_ERROR;
}
- r->header_size = p - r->header_start;
+ r->header_end = p;
r->header_in->pos = p + 1;
return NGX_OK;
@@ -2040,9 +2504,11 @@ ngx_http_spdy_parse_header(ngx_http_request_t *r)
if (ch == CR || ch == LF) {
return NGX_HTTP_PARSE_INVALID_HEADER;
}
+
+ p++;
}
- r->header_size = p - r->header_start;
+ r->header_end = p;
r->header_in->pos = p;
r->state = 0;
@@ -2091,7 +2557,7 @@ ngx_http_spdy_alloc_large_header_buffer(ngx_http_request_t *r)
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "spdy large header alloc: %p %uz",
+ "spdy large header alloc: %p %z",
buf->pos, buf->end - buf->last);
old = r->header_in->pos;
@@ -2101,13 +2567,6 @@ ngx_http_spdy_alloc_large_header_buffer(ngx_http_request_t *r)
buf->last = ngx_cpymem(new, old, rest);
}
- if (r->header_name_end > old) {
- r->header_name_end = new + (r->header_name_end - old);
-
- } else if (r->header_end > old) {
- r->header_end = new + (r->header_end - old);
- }
-
r->header_in = buf;
stream->header_buffers++;
@@ -2135,21 +2594,25 @@ ngx_http_spdy_handle_request_header(ngx_http_request_t *r)
return NGX_OK;
}
- } else {
+ }
+
+ if (r->header_name_start[0] == ':') {
+ r->header_name_start++;
+
for (i = 0; i < NGX_SPDY_REQUEST_HEADERS; i++) {
sh = &ngx_http_spdy_request_headers[i];
if (sh->hash != r->header_hash
- || sh->len != r->lowcase_index
- || ngx_strncmp(sh->header, r->header_name_start,
- r->lowcase_index)
- != 0)
+ || sh->len != r->header_name_end - r->header_name_start
+ || ngx_strncmp(sh->header, r->header_name_start, sh->len) != 0)
{
continue;
}
return sh->handler(r);
}
+
+ return NGX_HTTP_PARSE_INVALID_REQUEST;
}
h = ngx_list_push(&r->headers_in.headers);
@@ -2161,13 +2624,11 @@ ngx_http_spdy_handle_request_header(ngx_http_request_t *r)
h->hash = r->header_hash;
- h->key.len = r->lowcase_index;
+ h->key.len = r->header_name_end - r->header_name_start;
h->key.data = r->header_name_start;
- h->key.data[h->key.len] = '\0';
- h->value.len = r->header_size;
+ h->value.len = r->header_end - r->header_start;
h->value.data = r->header_start;
- h->value.data[h->value.len] = '\0';
h->lowcase_key = h->key.data;
@@ -2176,7 +2637,7 @@ ngx_http_spdy_handle_request_header(ngx_http_request_t *r)
void
-ngx_http_spdy_request_headers_init()
+ngx_http_spdy_request_headers_init(void)
{
ngx_uint_t i;
ngx_http_spdy_request_header_t *h;
@@ -2226,7 +2687,7 @@ ngx_http_spdy_parse_method(ngx_http_request_t *r)
return NGX_HTTP_PARSE_INVALID_HEADER;
}
- len = r->header_size;
+ len = r->header_end - r->header_start;
r->method_name.len = len;
r->method_name.data = r->header_start;
@@ -2287,7 +2748,39 @@ ngx_http_spdy_parse_scheme(ngx_http_request_t *r)
static ngx_int_t
-ngx_http_spdy_parse_url(ngx_http_request_t *r)
+ngx_http_spdy_parse_host(ngx_http_request_t *r)
+{
+ ngx_table_elt_t *h;
+
+ if (r->headers_in.host) {
+ return NGX_HTTP_PARSE_INVALID_HEADER;
+ }
+
+ h = ngx_list_push(&r->headers_in.headers);
+ if (h == NULL) {
+ ngx_http_spdy_close_stream(r->spdy_stream,
+ NGX_HTTP_INTERNAL_SERVER_ERROR);
+ return NGX_ERROR;
+ }
+
+ r->headers_in.host = h;
+
+ h->hash = r->header_hash;
+
+ h->key.len = r->header_name_end - r->header_name_start;
+ h->key.data = r->header_name_start;
+
+ h->value.len = r->header_end - r->header_start;
+ h->value.data = r->header_start;
+
+ h->lowcase_key = h->key.data;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_spdy_parse_path(ngx_http_request_t *r)
{
if (r->unparsed_uri.len) {
return NGX_HTTP_PARSE_INVALID_HEADER;
@@ -2319,7 +2812,7 @@ ngx_http_spdy_parse_version(ngx_http_request_t *r)
p = r->header_start;
- if (r->header_size < 8 || !(ngx_str5cmp(p, 'H', 'T', 'T', 'P', '/'))) {
+ if (r->header_end - p < 8 || !(ngx_str5cmp(p, 'H', 'T', 'T', 'P', '/'))) {
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
@@ -2335,6 +2828,10 @@ ngx_http_spdy_parse_version(ngx_http_request_t *r)
ch = *p;
+ if (ch == '.') {
+ break;
+ }
+
if (ch < '0' || ch > '9') {
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
@@ -2365,7 +2862,7 @@ ngx_http_spdy_parse_version(ngx_http_request_t *r)
r->http_minor = r->http_minor * 10 + ch - '0';
}
- r->http_protocol.len = r->header_size;
+ r->http_protocol.len = r->header_end - r->header_start;
r->http_protocol.data = r->header_start;
r->http_version = r->http_major * 1000 + r->http_minor;
@@ -2465,6 +2962,16 @@ ngx_http_spdy_run_request(ngx_http_request_t *r)
return;
}
+ if (r->headers_in.content_length_n > 0 && r->spdy_stream->in_closed) {
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client prematurely closed stream");
+
+ r->spdy_stream->skip_data = NGX_SPDY_DATA_ERROR;
+
+ ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
+ return;
+ }
+
ngx_http_process_request(r);
}
@@ -2597,10 +3104,55 @@ ngx_http_spdy_read_request_body(ngx_http_request_t *r,
r->request_body->post_handler = post_handler;
+ r->read_event_handler = ngx_http_test_reading;
+ r->write_event_handler = ngx_http_request_empty_handler;
+
return NGX_AGAIN;
}
+static ngx_int_t
+ngx_http_spdy_terminate_stream(ngx_http_spdy_connection_t *sc,
+ ngx_http_spdy_stream_t *stream, ngx_uint_t status)
+{
+ ngx_event_t *rev;
+ ngx_connection_t *fc;
+
+ if (ngx_http_spdy_send_rst_stream(sc, stream->id, status,
+ NGX_SPDY_HIGHEST_PRIORITY)
+ == NGX_ERROR)
+ {
+ return NGX_ERROR;
+ }
+
+ stream->out_closed = 1;
+
+ fc = stream->request->connection;
+ fc->error = 1;
+
+ rev = fc->read;
+ rev->handler(rev);
+
+ return NGX_OK;
+}
+
+
+static void
+ngx_http_spdy_close_stream_handler(ngx_event_t *ev)
+{
+ ngx_connection_t *fc;
+ ngx_http_request_t *r;
+
+ fc = ev->data;
+ r = fc->data;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "spdy close stream handler");
+
+ ngx_http_spdy_close_stream(r->spdy_stream, 0);
+}
+
+
void
ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc)
{
@@ -2612,9 +3164,16 @@ ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc)
sc = stream->connection;
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
- "spdy close stream %ui, processing %ui",
- stream->id, sc->processing);
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
+ "spdy close stream %ui, queued %ui, processing %ui",
+ stream->id, stream->queued, sc->processing);
+
+ fc = stream->request->connection;
+
+ if (stream->queued) {
+ fc->write->handler = ngx_http_spdy_close_stream_handler;
+ return;
+ }
if (!stream->out_closed) {
if (ngx_http_spdy_send_rst_stream(sc, stream->id,
@@ -2650,14 +3209,13 @@ ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc)
index = &s->index;
}
- fc = stream->request->connection;
-
ngx_http_free_request(stream->request, rc);
ev = fc->read;
if (ev->active || ev->disabled) {
- ngx_del_event(ev, NGX_READ_EVENT, 0);
+ ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0,
+ "spdy fake read event was activated");
}
if (ev->timer_set) {
@@ -2671,7 +3229,8 @@ ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc)
ev = fc->write;
if (ev->active || ev->disabled) {
- ngx_del_event(ev, NGX_WRITE_EVENT, 0);
+ ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0,
+ "spdy fake write event was activated");
}
if (ev->timer_set) {
@@ -2802,6 +3361,7 @@ ngx_http_spdy_finalize_connection(ngx_http_spdy_connection_t *sc,
c->error = 1;
c->read->handler = ngx_http_empty_handler;
+ c->write->handler = ngx_http_empty_handler;
sc->last_out = NULL;
@@ -2816,15 +3376,18 @@ ngx_http_spdy_finalize_connection(ngx_http_spdy_connection_t *sc,
stream = sc->streams_index[i];
while (stream) {
- r = stream->request;
+ stream->handled = 0;
+ r = stream->request;
fc = r->connection;
+
fc->error = 1;
- if (stream->waiting) {
- r->blocked -= stream->waiting;
- stream->waiting = 0;
+ if (stream->queued) {
+ stream->queued = 0;
+
ev = fc->write;
+ ev->delayed = 0;
} else {
ev = fc->read;
@@ -2847,6 +3410,61 @@ ngx_http_spdy_finalize_connection(ngx_http_spdy_connection_t *sc,
}
+static ngx_int_t
+ngx_http_spdy_adjust_windows(ngx_http_spdy_connection_t *sc, ssize_t delta)
+{
+ ngx_uint_t i, size;
+ ngx_event_t *wev;
+ ngx_http_spdy_stream_t *stream, *sn;
+ ngx_http_spdy_srv_conf_t *sscf;
+
+ sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
+ ngx_http_spdy_module);
+
+ size = ngx_http_spdy_streams_index_size(sscf);
+
+ for (i = 0; i < size; i++) {
+
+ for (stream = sc->streams_index[i]; stream; stream = sn) {
+ sn = stream->index;
+
+ if (delta > 0
+ && stream->send_window
+ > (ssize_t) (NGX_SPDY_MAX_WINDOW - delta))
+ {
+ if (ngx_http_spdy_terminate_stream(sc, stream,
+ NGX_SPDY_FLOW_CONTROL_ERROR)
+ == NGX_ERROR)
+ {
+ return NGX_ERROR;
+ }
+
+ continue;
+ }
+
+ stream->send_window += delta;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
+ "spdy:%ui adjust window:%z",
+ stream->id, stream->send_window);
+
+ if (stream->send_window > 0 && stream->exhausted) {
+ stream->exhausted = 0;
+
+ wev = stream->request->connection->write;
+
+ if (!wev->timer_set) {
+ wev->delayed = 0;
+ wev->handler(wev);
+ }
+ }
+ }
+ }
+
+ return NGX_OK;
+}
+
+
static void
ngx_http_spdy_pool_cleanup(void *data)
{
diff --git a/usr.sbin/nginx/src/http/ngx_http_spdy.h b/usr.sbin/nginx/src/http/ngx_http_spdy.h
index 4294e3d5078..55aceda8999 100644
--- a/usr.sbin/nginx/src/http/ngx_http_spdy.h
+++ b/usr.sbin/nginx/src/http/ngx_http_spdy.h
@@ -15,12 +15,10 @@
#include <zlib.h>
-#define NGX_SPDY_VERSION 2
+#define NGX_SPDY_VERSION 3
-#ifdef TLSEXT_TYPE_next_proto_neg
-#define NGX_SPDY_NPN_ADVERTISE "\x06spdy/2"
-#define NGX_SPDY_NPN_NEGOTIATED "spdy/2"
-#endif
+#define NGX_SPDY_NPN_ADVERTISE "\x08spdy/3.1"
+#define NGX_SPDY_NPN_NEGOTIATED "spdy/3.1"
#define NGX_SPDY_STATE_BUFFER_SIZE 16
@@ -30,32 +28,34 @@
#define NGX_SPDY_SYN_REPLY 2
#define NGX_SPDY_RST_STREAM 3
#define NGX_SPDY_SETTINGS 4
-#define NGX_SPDY_NOOP 5
#define NGX_SPDY_PING 6
#define NGX_SPDY_GOAWAY 7
#define NGX_SPDY_HEADERS 8
+#define NGX_SPDY_WINDOW_UPDATE 9
#define NGX_SPDY_FRAME_HEADER_SIZE 8
#define NGX_SPDY_SID_SIZE 4
+#define NGX_SPDY_DELTA_SIZE 4
#define NGX_SPDY_SYN_STREAM_SIZE 10
-#define NGX_SPDY_SYN_REPLY_SIZE 6
+#define NGX_SPDY_SYN_REPLY_SIZE 4
#define NGX_SPDY_RST_STREAM_SIZE 8
#define NGX_SPDY_PING_SIZE 4
-#define NGX_SPDY_GOAWAY_SIZE 4
-#define NGX_SPDY_NV_NUM_SIZE 2
-#define NGX_SPDY_NV_NLEN_SIZE 2
-#define NGX_SPDY_NV_VLEN_SIZE 2
+#define NGX_SPDY_GOAWAY_SIZE 8
+#define NGX_SPDY_WINDOW_UPDATE_SIZE 8
+#define NGX_SPDY_NV_NUM_SIZE 4
+#define NGX_SPDY_NV_NLEN_SIZE 4
+#define NGX_SPDY_NV_VLEN_SIZE 4
#define NGX_SPDY_SETTINGS_NUM_SIZE 4
-#define NGX_SPDY_SETTINGS_IDF_SIZE 4
+#define NGX_SPDY_SETTINGS_FID_SIZE 4
#define NGX_SPDY_SETTINGS_VAL_SIZE 4
#define NGX_SPDY_SETTINGS_PAIR_SIZE \
- (NGX_SPDY_SETTINGS_IDF_SIZE + NGX_SPDY_SETTINGS_VAL_SIZE)
+ (NGX_SPDY_SETTINGS_FID_SIZE + NGX_SPDY_SETTINGS_VAL_SIZE)
#define NGX_SPDY_HIGHEST_PRIORITY 0
-#define NGX_SPDY_LOWEST_PRIORITY 3
+#define NGX_SPDY_LOWEST_PRIORITY 7
#define NGX_SPDY_FLAG_FIN 0x01
#define NGX_SPDY_FLAG_UNIDIRECTIONAL 0x02
@@ -81,6 +81,12 @@ struct ngx_http_spdy_connection_s {
ngx_uint_t processing;
+ size_t send_window;
+ size_t recv_window;
+ size_t init_window;
+
+ ngx_queue_t waiting;
+
u_char buffer[NGX_SPDY_STATE_BUFFER_SIZE];
size_t buffer_used;
ngx_http_spdy_handler_pt handler;
@@ -96,18 +102,19 @@ struct ngx_http_spdy_connection_s {
ngx_http_spdy_stream_t **streams_index;
ngx_http_spdy_out_frame_t *last_out;
- ngx_http_spdy_stream_t *last_stream;
+
+ ngx_queue_t posted;
ngx_http_spdy_stream_t *stream;
- ngx_uint_t headers;
+ ngx_uint_t entries;
size_t length;
u_char flags;
ngx_uint_t last_sid;
- unsigned blocked:2;
- unsigned waiting:1; /* FIXME better name */
+ unsigned blocked:1;
+ unsigned incomplete:1;
};
@@ -116,15 +123,27 @@ struct ngx_http_spdy_stream_s {
ngx_http_request_t *request;
ngx_http_spdy_connection_t *connection;
ngx_http_spdy_stream_t *index;
- ngx_http_spdy_stream_t *next;
ngx_uint_t header_buffers;
- ngx_uint_t waiting;
+ ngx_uint_t queued;
+
+ /*
+ * A change to SETTINGS_INITIAL_WINDOW_SIZE could cause the
+ * send_window to become negative, hence it's signed.
+ */
+ ssize_t send_window;
+ size_t recv_window;
+
ngx_http_spdy_out_frame_t *free_frames;
ngx_chain_t *free_data_headers;
+ ngx_chain_t *free_bufs;
- unsigned priority:2;
+ ngx_queue_t queue;
+
+ unsigned priority:3;
unsigned handled:1;
+ unsigned blocked:1;
+ unsigned exhausted:1;
unsigned in_closed:1;
unsigned out_closed:1;
unsigned skip_data:2;
@@ -138,10 +157,8 @@ struct ngx_http_spdy_out_frame_s {
ngx_int_t (*handler)(ngx_http_spdy_connection_t *sc,
ngx_http_spdy_out_frame_t *frame);
- ngx_http_spdy_out_frame_t *free;
-
ngx_http_spdy_stream_t *stream;
- size_t size;
+ size_t length;
ngx_uint_t priority;
unsigned blocked:1;
@@ -157,6 +174,9 @@ ngx_http_spdy_queue_frame(ngx_http_spdy_connection_t *sc,
for (out = &sc->last_out; *out; out = &(*out)->next)
{
+ /*
+ * NB: higher values represent lower priorities.
+ */
if (frame->priority >= (*out)->priority) {
break;
}
@@ -173,9 +193,9 @@ ngx_http_spdy_queue_blocked_frame(ngx_http_spdy_connection_t *sc,
{
ngx_http_spdy_out_frame_t **out;
- for (out = &sc->last_out; *out && !(*out)->blocked; out = &(*out)->next)
+ for (out = &sc->last_out; *out; out = &(*out)->next)
{
- if (frame->priority >= (*out)->priority) {
+ if ((*out)->blocked) {
break;
}
}
@@ -186,7 +206,7 @@ ngx_http_spdy_queue_blocked_frame(ngx_http_spdy_connection_t *sc,
void ngx_http_spdy_init(ngx_event_t *rev);
-void ngx_http_spdy_request_headers_init();
+void ngx_http_spdy_request_headers_init(void);
ngx_int_t ngx_http_spdy_read_request_body(ngx_http_request_t *r,
ngx_http_client_body_handler_pt post_handler);
@@ -229,7 +249,10 @@ ngx_int_t ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc);
#define ngx_spdy_frame_write_flags_and_len(p, f, l) \
ngx_spdy_frame_aligned_write_uint32(p, (f) << 24 | (l))
+#define ngx_spdy_frame_write_flags_and_id(p, f, i) \
+ ngx_spdy_frame_aligned_write_uint32(p, (f) << 24 | (i))
-#define ngx_spdy_frame_write_sid ngx_spdy_frame_aligned_write_uint32
+#define ngx_spdy_frame_write_sid ngx_spdy_frame_aligned_write_uint32
+#define ngx_spdy_frame_write_window ngx_spdy_frame_aligned_write_uint32
#endif /* _NGX_HTTP_SPDY_H_INCLUDED_ */
diff --git a/usr.sbin/nginx/src/http/ngx_http_spdy_filter_module.c b/usr.sbin/nginx/src/http/ngx_http_spdy_filter_module.c
index 8fe46b2e954..559fb4aab9a 100644
--- a/usr.sbin/nginx/src/http/ngx_http_spdy_filter_module.c
+++ b/usr.sbin/nginx/src/http/ngx_http_spdy_filter_module.c
@@ -14,14 +14,12 @@
#include <zlib.h>
-#define NGX_SPDY_WRITE_BUFFERED NGX_HTTP_WRITE_BUFFERED
-
#define ngx_http_spdy_nv_nsize(h) (NGX_SPDY_NV_NLEN_SIZE + sizeof(h) - 1)
#define ngx_http_spdy_nv_vsize(h) (NGX_SPDY_NV_VLEN_SIZE + sizeof(h) - 1)
-#define ngx_http_spdy_nv_write_num ngx_spdy_frame_write_uint16
-#define ngx_http_spdy_nv_write_nlen ngx_spdy_frame_write_uint16
-#define ngx_http_spdy_nv_write_vlen ngx_spdy_frame_write_uint16
+#define ngx_http_spdy_nv_write_num ngx_spdy_frame_write_uint32
+#define ngx_http_spdy_nv_write_nlen ngx_spdy_frame_write_uint32
+#define ngx_http_spdy_nv_write_vlen ngx_spdy_frame_write_uint32
#define ngx_http_spdy_nv_write_name(p, h) \
ngx_cpymem(ngx_http_spdy_nv_write_nlen(p, sizeof(h) - 1), h, sizeof(h) - 1)
@@ -29,12 +27,22 @@
#define ngx_http_spdy_nv_write_val(p, h) \
ngx_cpymem(ngx_http_spdy_nv_write_vlen(p, sizeof(h) - 1), h, sizeof(h) - 1)
+
+static ngx_chain_t *ngx_http_spdy_send_chain(ngx_connection_t *fc,
+ ngx_chain_t *in, off_t limit);
+
static ngx_inline ngx_int_t ngx_http_spdy_filter_send(
ngx_connection_t *fc, ngx_http_spdy_stream_t *stream);
+static ngx_inline ngx_int_t ngx_http_spdy_flow_control(
+ ngx_http_spdy_connection_t *sc, ngx_http_spdy_stream_t *stream);
+static void ngx_http_spdy_waiting_queue(ngx_http_spdy_connection_t *sc,
+ ngx_http_spdy_stream_t *stream);
+static ngx_chain_t *ngx_http_spdy_filter_get_shadow(
+ ngx_http_spdy_stream_t *stream, ngx_buf_t *buf, off_t offset, off_t size);
static ngx_http_spdy_out_frame_t *ngx_http_spdy_filter_get_data_frame(
- ngx_http_spdy_stream_t *stream, size_t len, ngx_uint_t flags,
- ngx_chain_t *first, ngx_chain_t *last);
+ ngx_http_spdy_stream_t *stream, size_t len, ngx_chain_t *first,
+ ngx_chain_t *last);
static ngx_int_t ngx_http_spdy_syn_frame_handler(
ngx_http_spdy_connection_t *sc, ngx_http_spdy_out_frame_t *frame);
@@ -82,7 +90,6 @@ ngx_module_t ngx_http_spdy_filter_module = {
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
-static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
static ngx_int_t
@@ -159,10 +166,12 @@ ngx_http_spdy_header_filter(ngx_http_request_t *r)
}
len = NGX_SPDY_NV_NUM_SIZE
- + ngx_http_spdy_nv_nsize("version")
+ + ngx_http_spdy_nv_nsize(":version")
+ ngx_http_spdy_nv_vsize("HTTP/1.1")
- + ngx_http_spdy_nv_nsize("status")
- + ngx_http_spdy_nv_vsize("418");
+ + ngx_http_spdy_nv_nsize(":status")
+ + (r->headers_out.status_line.len
+ ? NGX_SPDY_NV_VLEN_SIZE + r->headers_out.status_line.len
+ : ngx_http_spdy_nv_vsize("418"));
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
@@ -300,12 +309,20 @@ ngx_http_spdy_header_filter(ngx_http_request_t *r)
last = buf + NGX_SPDY_NV_NUM_SIZE;
- last = ngx_http_spdy_nv_write_name(last, "version");
+ last = ngx_http_spdy_nv_write_name(last, ":version");
last = ngx_http_spdy_nv_write_val(last, "HTTP/1.1");
- last = ngx_http_spdy_nv_write_name(last, "status");
- last = ngx_spdy_frame_write_uint16(last, 3);
- last = ngx_sprintf(last, "%03ui", r->headers_out.status);
+ last = ngx_http_spdy_nv_write_name(last, ":status");
+
+ if (r->headers_out.status_line.len) {
+ last = ngx_http_spdy_nv_write_vlen(last,
+ r->headers_out.status_line.len);
+ last = ngx_cpymem(last, r->headers_out.status_line.data,
+ r->headers_out.status_line.len);
+ } else {
+ last = ngx_http_spdy_nv_write_vlen(last, 3);
+ last = ngx_sprintf(last, "%03ui", r->headers_out.status);
+ }
count = 2;
@@ -444,17 +461,6 @@ ngx_http_spdy_header_filter(ngx_http_request_t *r)
continue;
}
- if ((header[i].key.len == 6
- && ngx_strncasecmp(header[i].key.data,
- (u_char *) "status", 6) == 0)
- || (header[i].key.len == 7
- && ngx_strncasecmp(header[i].key.data,
- (u_char *) "version", 7) == 0))
- {
- header[i].hash = 0;
- continue;
- }
-
last = ngx_http_spdy_nv_write_nlen(last, header[i].key.len);
ngx_strlow(last, header[i].key.data, header[i].key.len);
@@ -500,7 +506,7 @@ ngx_http_spdy_header_filter(ngx_http_request_t *r)
count++;
}
- (void) ngx_spdy_frame_write_uint16(buf, count);
+ (void) ngx_http_spdy_nv_write_num(buf, count);
stream = r->spdy_stream;
sc = stream->connection;
@@ -547,13 +553,14 @@ ngx_http_spdy_header_filter(ngx_http_request_t *r)
r->header_size = len;
+ len -= NGX_SPDY_FRAME_HEADER_SIZE;
+
if (r->header_only) {
b->last_buf = 1;
- p = ngx_spdy_frame_write_flags_and_len(p, NGX_SPDY_FLAG_FIN,
- len - NGX_SPDY_FRAME_HEADER_SIZE);
+ p = ngx_spdy_frame_write_flags_and_len(p, NGX_SPDY_FLAG_FIN, len);
+
} else {
- p = ngx_spdy_frame_write_flags_and_len(p, 0,
- len - NGX_SPDY_FRAME_HEADER_SIZE);
+ p = ngx_spdy_frame_write_flags_and_len(p, 0, len);
}
(void) ngx_spdy_frame_write_sid(p, stream->id);
@@ -574,21 +581,18 @@ ngx_http_spdy_header_filter(ngx_http_request_t *r)
frame->first = cl;
frame->last = cl;
frame->handler = ngx_http_spdy_syn_frame_handler;
- frame->free = NULL;
frame->stream = stream;
- frame->size = len;
+ frame->length = len;
frame->priority = stream->priority;
frame->blocked = 1;
frame->fin = r->header_only;
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, stream->request->connection->log, 0,
- "spdy:%ui create SYN_REPLY frame %p: size:%uz",
- stream->id, frame, frame->size);
+ "spdy:%ui create SYN_REPLY frame %p: len:%uz",
+ stream->id, frame, frame->length);
ngx_http_spdy_queue_blocked_frame(sc, frame);
- r->blocked++;
-
cln = ngx_http_cleanup_add(r, 0);
if (cln == NULL) {
return NGX_ERROR;
@@ -597,109 +601,240 @@ ngx_http_spdy_header_filter(ngx_http_request_t *r)
cln->handler = ngx_http_spdy_filter_cleanup;
cln->data = stream;
- stream->waiting = 1;
+ stream->queued = 1;
+
+ c->send_chain = ngx_http_spdy_send_chain;
+ c->need_last_buf = 1;
return ngx_http_spdy_filter_send(c, stream);
}
-static ngx_int_t
-ngx_http_spdy_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
+static ngx_chain_t *
+ngx_http_spdy_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit)
{
- off_t size;
- ngx_buf_t *b;
- ngx_chain_t *cl, *ll, *out, **ln;
- ngx_http_spdy_stream_t *stream;
- ngx_http_spdy_out_frame_t *frame;
-
+ off_t size, offset;
+ size_t rest, frame_size;
+ ngx_chain_t *cl, *out, **ln;
+ ngx_http_request_t *r;
+ ngx_http_spdy_stream_t *stream;
+ ngx_http_spdy_loc_conf_t *slcf;
+ ngx_http_spdy_out_frame_t *frame;
+ ngx_http_spdy_connection_t *sc;
+
+ r = fc->data;
stream = r->spdy_stream;
- if (stream == NULL) {
- return ngx_http_next_body_filter(r, in);
+#if (NGX_SUPPRESS_WARN)
+ size = 0;
+#endif
+
+ while (in) {
+ size = ngx_buf_size(in->buf);
+
+ if (size || in->buf->last_buf) {
+ break;
+ }
+
+ in = in->next;
}
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "spdy body filter \"%V?%V\"", &r->uri, &r->args);
+ if (in == NULL) {
- if (in == NULL || r->header_only) {
+ if (stream->queued) {
+ fc->write->delayed = 1;
+ } else {
+ fc->buffered &= ~NGX_SPDY_BUFFERED;
+ }
- if (stream->waiting) {
- return NGX_AGAIN;
+ return NULL;
+ }
+
+ sc = stream->connection;
+
+ if (size && ngx_http_spdy_flow_control(sc, stream) == NGX_DECLINED) {
+ fc->write->delayed = 1;
+ return in;
+ }
+
+ if (limit == 0 || limit > (off_t) sc->send_window) {
+ limit = sc->send_window;
+ }
+
+ if (limit > stream->send_window) {
+ limit = (stream->send_window > 0) ? stream->send_window : 0;
+ }
+
+ if (in->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_get_shadow) {
+ cl = ngx_alloc_chain_link(r->pool);
+ if (cl == NULL) {
+ return NGX_CHAIN_ERROR;
}
- r->connection->buffered &= ~NGX_SPDY_WRITE_BUFFERED;
+ cl->buf = in->buf;
+ in->buf = cl->buf->shadow;
- return NGX_OK;
+ offset = ngx_buf_in_memory(in->buf)
+ ? (cl->buf->pos - in->buf->pos)
+ : (cl->buf->file_pos - in->buf->file_pos);
+
+ cl->next = stream->free_bufs;
+ stream->free_bufs = cl;
+
+ } else {
+ offset = 0;
}
- size = 0;
- ln = &out;
- ll = in;
+#if (NGX_SUPPRESS_WARN)
+ cl = NULL;
+#endif
+
+ slcf = ngx_http_get_module_loc_conf(r, ngx_http_spdy_module);
+
+ frame_size = (limit <= (off_t) slcf->chunk_size) ? (size_t) limit
+ : slcf->chunk_size;
for ( ;; ) {
- b = ll->buf;
-#if 1
- if (ngx_buf_size(b) == 0 && !ngx_buf_special(b)) {
- ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
- "zero size buf in spdy body filter "
- "t:%d r:%d f:%d %p %p-%p %p %O-%O",
- b->temporary,
- b->recycled,
- b->in_file,
- b->start,
- b->pos,
- b->last,
- b->file,
- b->file_pos,
- b->file_last);
-
- ngx_debug_point();
- return NGX_ERROR;
+ ln = &out;
+ rest = frame_size;
+
+ while ((off_t) rest >= size) {
+
+ if (offset) {
+ cl = ngx_http_spdy_filter_get_shadow(stream, in->buf,
+ offset, size);
+ if (cl == NULL) {
+ return NGX_CHAIN_ERROR;
+ }
+
+ offset = 0;
+
+ } else {
+ cl = ngx_alloc_chain_link(r->pool);
+ if (cl == NULL) {
+ return NGX_CHAIN_ERROR;
+ }
+
+ cl->buf = in->buf;
+ }
+
+ *ln = cl;
+ ln = &cl->next;
+
+ rest -= (size_t) size;
+ in = in->next;
+
+ if (in == NULL) {
+ frame_size -= rest;
+ rest = 0;
+ break;
+ }
+
+ size = ngx_buf_size(in->buf);
}
-#endif
- cl = ngx_alloc_chain_link(r->pool);
- if (cl == NULL) {
- return NGX_ERROR;
+
+ if (rest) {
+ cl = ngx_http_spdy_filter_get_shadow(stream, in->buf,
+ offset, rest);
+ if (cl == NULL) {
+ return NGX_CHAIN_ERROR;
+ }
+
+ cl->buf->flush = 0;
+ cl->buf->last_buf = 0;
+
+ *ln = cl;
+
+ offset += rest;
+ size -= rest;
}
- size += ngx_buf_size(b);
- cl->buf = b;
+ frame = ngx_http_spdy_filter_get_data_frame(stream, frame_size,
+ out, cl);
+ if (frame == NULL) {
+ return NGX_CHAIN_ERROR;
+ }
+
+ ngx_http_spdy_queue_frame(sc, frame);
+
+ sc->send_window -= frame_size;
+
+ stream->send_window -= frame_size;
+ stream->queued++;
+
+ if (in == NULL) {
+ break;
+ }
- *ln = cl;
- ln = &cl->next;
+ limit -= frame_size;
- if (ll->next == NULL) {
+ if (limit == 0) {
break;
}
- ll = ll->next;
+ if (limit < (off_t) slcf->chunk_size) {
+ frame_size = (size_t) limit;
+ }
}
- if (size > NGX_SPDY_MAX_FRAME_SIZE) {
- ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
- "FIXME: chain too big in spdy filter: %O", size);
- return NGX_ERROR;
+ if (offset) {
+ cl = ngx_http_spdy_filter_get_shadow(stream, in->buf, offset, size);
+ if (cl == NULL) {
+ return NGX_CHAIN_ERROR;
+ }
+
+ in->buf = cl->buf;
+ ngx_free_chain(r->pool, cl);
}
- frame = ngx_http_spdy_filter_get_data_frame(stream, (size_t) size,
- b->last_buf, out, cl);
- if (frame == NULL) {
- return NGX_ERROR;
+ if (ngx_http_spdy_filter_send(fc, stream) == NGX_ERROR) {
+ return NGX_CHAIN_ERROR;
+ }
+
+ if (in && ngx_http_spdy_flow_control(sc, stream) == NGX_DECLINED) {
+ fc->write->delayed = 1;
}
- ngx_http_spdy_queue_frame(stream->connection, frame);
+ return in;
+}
+
+
+static ngx_chain_t *
+ngx_http_spdy_filter_get_shadow(ngx_http_spdy_stream_t *stream, ngx_buf_t *buf,
+ off_t offset, off_t size)
+{
+ ngx_buf_t *chunk;
+ ngx_chain_t *cl;
+
+ cl = ngx_chain_get_free_buf(stream->request->pool, &stream->free_bufs);
+ if (cl == NULL) {
+ return NULL;
+ }
+
+ chunk = cl->buf;
+
+ ngx_memcpy(chunk, buf, sizeof(ngx_buf_t));
- stream->waiting++;
+ chunk->tag = (ngx_buf_tag_t) &ngx_http_spdy_filter_get_shadow;
+ chunk->shadow = buf;
- r->main->blocked++;
+ if (ngx_buf_in_memory(chunk)) {
+ chunk->pos += offset;
+ chunk->last = chunk->pos + size;
+ }
+
+ if (chunk->in_file) {
+ chunk->file_pos += offset;
+ chunk->file_last = chunk->file_pos + size;
+ }
- return ngx_http_spdy_filter_send(r->connection, stream);
+ return cl;
}
static ngx_http_spdy_out_frame_t *
ngx_http_spdy_filter_get_data_frame(ngx_http_spdy_stream_t *stream,
- size_t len, ngx_uint_t fin, ngx_chain_t *first, ngx_chain_t *last)
+ size_t len, ngx_chain_t *first, ngx_chain_t *last)
{
u_char *p;
ngx_buf_t *buf;
@@ -711,7 +846,7 @@ ngx_http_spdy_filter_get_data_frame(ngx_http_spdy_stream_t *stream,
frame = stream->free_frames;
if (frame) {
- stream->free_frames = frame->free;
+ stream->free_frames = frame->next;
} else {
frame = ngx_palloc(stream->request->pool,
@@ -721,62 +856,60 @@ ngx_http_spdy_filter_get_data_frame(ngx_http_spdy_stream_t *stream,
}
}
+ flags = last->buf->last_buf ? NGX_SPDY_FLAG_FIN : 0;
+
ngx_log_debug4(NGX_LOG_DEBUG_HTTP, stream->request->connection->log, 0,
- "spdy:%ui create DATA frame %p: len:%uz fin:%ui",
- stream->id, frame, len, fin);
+ "spdy:%ui create DATA frame %p: len:%uz flags:%ui",
+ stream->id, frame, len, flags);
- if (len || fin) {
+ cl = ngx_chain_get_free_buf(stream->request->pool,
+ &stream->free_data_headers);
+ if (cl == NULL) {
+ return NULL;
+ }
- flags = fin ? NGX_SPDY_FLAG_FIN : 0;
+ buf = cl->buf;
- cl = ngx_chain_get_free_buf(stream->request->pool,
- &stream->free_data_headers);
- if (cl == NULL) {
- return NULL;
- }
+ if (buf->start) {
+ p = buf->start;
+ buf->pos = p;
- buf = cl->buf;
+ p += NGX_SPDY_SID_SIZE;
- if (buf->start) {
- p = buf->start;
- buf->pos = p;
+ (void) ngx_spdy_frame_write_flags_and_len(p, flags, len);
- p += sizeof(uint32_t);
+ } else {
+ p = ngx_palloc(stream->request->pool, NGX_SPDY_FRAME_HEADER_SIZE);
+ if (p == NULL) {
+ return NULL;
+ }
- (void) ngx_spdy_frame_write_flags_and_len(p, flags, len);
+ buf->pos = p;
+ buf->start = p;
- } else {
- p = ngx_palloc(stream->request->pool, NGX_SPDY_FRAME_HEADER_SIZE);
- if (p == NULL) {
- return NULL;
- }
+ p = ngx_spdy_frame_write_sid(p, stream->id);
+ p = ngx_spdy_frame_write_flags_and_len(p, flags, len);
- buf->pos = p;
- buf->start = p;
+ buf->last = p;
+ buf->end = p;
- p = ngx_spdy_frame_write_sid(p, stream->id);
- p = ngx_spdy_frame_write_flags_and_len(p, flags, len);
-
- buf->last = p;
- buf->end = p;
+ buf->tag = (ngx_buf_tag_t) &ngx_http_spdy_filter_get_data_frame;
+ buf->memory = 1;
+ }
- buf->tag = (ngx_buf_tag_t) &ngx_http_spdy_filter_module;
- buf->memory = 1;
- }
+ cl->next = first;
+ first = cl;
- cl->next = first;
- first = cl;
- }
+ last->buf->flush = 1;
frame->first = first;
frame->last = last;
frame->handler = ngx_http_spdy_data_frame_handler;
- frame->free = NULL;
frame->stream = stream;
- frame->size = NGX_SPDY_FRAME_HEADER_SIZE + len;
+ frame->length = len;
frame->priority = stream->priority;
frame->blocked = 0;
- frame->fin = fin;
+ frame->fin = last->buf->last_buf;
return frame;
}
@@ -785,23 +918,76 @@ ngx_http_spdy_filter_get_data_frame(ngx_http_spdy_stream_t *stream,
static ngx_inline ngx_int_t
ngx_http_spdy_filter_send(ngx_connection_t *fc, ngx_http_spdy_stream_t *stream)
{
+ stream->blocked = 1;
+
if (ngx_http_spdy_send_output_queue(stream->connection) == NGX_ERROR) {
fc->error = 1;
return NGX_ERROR;
}
- if (stream->waiting) {
- fc->buffered |= NGX_SPDY_WRITE_BUFFERED;
+ stream->blocked = 0;
+
+ if (stream->queued) {
+ fc->buffered |= NGX_SPDY_BUFFERED;
fc->write->delayed = 1;
return NGX_AGAIN;
}
- fc->buffered &= ~NGX_SPDY_WRITE_BUFFERED;
+ fc->buffered &= ~NGX_SPDY_BUFFERED;
+
+ return NGX_OK;
+}
+
+
+static ngx_inline ngx_int_t
+ngx_http_spdy_flow_control(ngx_http_spdy_connection_t *sc,
+ ngx_http_spdy_stream_t *stream)
+{
+ if (stream->send_window <= 0) {
+ stream->exhausted = 1;
+ return NGX_DECLINED;
+ }
+
+ if (sc->send_window == 0) {
+ ngx_http_spdy_waiting_queue(sc, stream);
+ return NGX_DECLINED;
+ }
return NGX_OK;
}
+static void
+ngx_http_spdy_waiting_queue(ngx_http_spdy_connection_t *sc,
+ ngx_http_spdy_stream_t *stream)
+{
+ ngx_queue_t *q;
+ ngx_http_spdy_stream_t *s;
+
+ if (stream->handled) {
+ return;
+ }
+
+ stream->handled = 1;
+
+ for (q = ngx_queue_last(&sc->waiting);
+ q != ngx_queue_sentinel(&sc->waiting);
+ q = ngx_queue_prev(q))
+ {
+ s = ngx_queue_data(q, ngx_http_spdy_stream_t, queue);
+
+ /*
+ * NB: higher values represent lower priorities.
+ */
+ if (stream->priority >= s->priority) {
+ break;
+ }
+ }
+
+ ngx_queue_insert_after(q, &stream->queue);
+}
+
+
static ngx_int_t
ngx_http_spdy_syn_frame_handler(ngx_http_spdy_connection_t *sc,
ngx_http_spdy_out_frame_t *frame)
@@ -834,6 +1020,7 @@ static ngx_int_t
ngx_http_spdy_data_frame_handler(ngx_http_spdy_connection_t *sc,
ngx_http_spdy_out_frame_t *frame)
{
+ ngx_buf_t *buf;
ngx_chain_t *cl, *ln;
ngx_http_spdy_stream_t *stream;
@@ -841,7 +1028,7 @@ ngx_http_spdy_data_frame_handler(ngx_http_spdy_connection_t *sc,
cl = frame->first;
- if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_module) {
+ if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_get_data_frame) {
if (cl->buf->pos != cl->buf->last) {
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
@@ -864,6 +1051,18 @@ ngx_http_spdy_data_frame_handler(ngx_http_spdy_connection_t *sc,
}
for ( ;; ) {
+ if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_get_shadow) {
+ buf = cl->buf->shadow;
+
+ if (ngx_buf_in_memory(buf)) {
+ buf->pos = cl->buf->pos;
+ }
+
+ if (buf->in_file) {
+ buf->file_pos = cl->buf->file_pos;
+ }
+ }
+
if (ngx_buf_size(cl->buf) != 0) {
if (cl != frame->first) {
@@ -880,7 +1079,13 @@ ngx_http_spdy_data_frame_handler(ngx_http_spdy_connection_t *sc,
ln = cl->next;
- ngx_free_chain(stream->request->pool, cl);
+ if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_get_shadow) {
+ cl->next = stream->free_bufs;
+ stream->free_bufs = cl;
+
+ } else {
+ ngx_free_chain(stream->request->pool, cl);
+ }
if (cl == frame->last) {
goto done;
@@ -912,17 +1117,16 @@ ngx_http_spdy_handle_frame(ngx_http_spdy_stream_t *stream,
r = stream->request;
- r->connection->sent += frame->size;
- r->blocked--;
+ r->connection->sent += NGX_SPDY_FRAME_HEADER_SIZE + frame->length;
if (frame->fin) {
stream->out_closed = 1;
}
- frame->free = stream->free_frames;
+ frame->next = stream->free_frames;
stream->free_frames = frame;
- stream->waiting--;
+ stream->queued--;
}
@@ -930,21 +1134,19 @@ static ngx_inline void
ngx_http_spdy_handle_stream(ngx_http_spdy_connection_t *sc,
ngx_http_spdy_stream_t *stream)
{
- ngx_connection_t *fc;
-
- fc = stream->request->connection;
-
- fc->write->delayed = 0;
+ ngx_event_t *wev;
- if (stream->handled) {
+ if (stream->handled || stream->blocked || stream->exhausted) {
return;
}
- if (sc->blocked == 2) {
- stream->handled = 1;
+ wev = stream->request->connection->write;
+
+ if (!wev->timer_set) {
+ wev->delayed = 0;
- stream->next = sc->last_stream;
- sc->last_stream = stream;
+ stream->handled = 1;
+ ngx_queue_insert_tail(&sc->posted, &stream->queue);
}
}
@@ -954,16 +1156,22 @@ ngx_http_spdy_filter_cleanup(void *data)
{
ngx_http_spdy_stream_t *stream = data;
- ngx_http_request_t *r;
- ngx_http_spdy_out_frame_t *frame, **fn;
+ size_t delta;
+ ngx_http_spdy_out_frame_t *frame, **fn;
+ ngx_http_spdy_connection_t *sc;
- if (stream->waiting == 0) {
- return;
+ if (stream->handled) {
+ stream->handled = 0;
+ ngx_queue_remove(&stream->queue);
}
- r = stream->request;
+ if (stream->queued == 0) {
+ return;
+ }
- fn = &stream->connection->last_out;
+ delta = 0;
+ sc = stream->connection;
+ fn = &sc->last_out;
for ( ;; ) {
frame = *fn;
@@ -973,16 +1181,26 @@ ngx_http_spdy_filter_cleanup(void *data)
}
if (frame->stream == stream && !frame->blocked) {
+ *fn = frame->next;
- stream->waiting--;
- r->blocked--;
+ delta += frame->length;
+
+ if (--stream->queued == 0) {
+ break;
+ }
- *fn = frame->next;
continue;
}
fn = &frame->next;
}
+
+ if (sc->send_window == 0 && delta && !ngx_queue_empty(&sc->waiting)) {
+ ngx_queue_add(&sc->posted, &sc->waiting);
+ ngx_queue_init(&sc->waiting);
+ }
+
+ sc->send_window += delta;
}
@@ -992,8 +1210,5 @@ ngx_http_spdy_filter_init(ngx_conf_t *cf)
ngx_http_next_header_filter = ngx_http_top_header_filter;
ngx_http_top_header_filter = ngx_http_spdy_header_filter;
- ngx_http_next_body_filter = ngx_http_top_body_filter;
- ngx_http_top_body_filter = ngx_http_spdy_body_filter;
-
return NGX_OK;
}
diff --git a/usr.sbin/nginx/src/http/ngx_http_spdy_module.c b/usr.sbin/nginx/src/http/ngx_http_spdy_module.c
index 7f02a18ca0c..5178a36f239 100644
--- a/usr.sbin/nginx/src/http/ngx_http_spdy_module.c
+++ b/usr.sbin/nginx/src/http/ngx_http_spdy_module.c
@@ -22,16 +22,19 @@ static ngx_int_t ngx_http_spdy_module_init(ngx_cycle_t *cycle);
static void *ngx_http_spdy_create_main_conf(ngx_conf_t *cf);
static char *ngx_http_spdy_init_main_conf(ngx_conf_t *cf, void *conf);
-
static void *ngx_http_spdy_create_srv_conf(ngx_conf_t *cf);
static char *ngx_http_spdy_merge_srv_conf(ngx_conf_t *cf, void *parent,
void *child);
+static void *ngx_http_spdy_create_loc_conf(ngx_conf_t *cf);
+static char *ngx_http_spdy_merge_loc_conf(ngx_conf_t *cf, void *parent,
+ void *child);
static char *ngx_http_spdy_recv_buffer_size(ngx_conf_t *cf, void *post,
void *data);
static char *ngx_http_spdy_pool_size(ngx_conf_t *cf, void *post, void *data);
static char *ngx_http_spdy_streams_index_mask(ngx_conf_t *cf, void *post,
void *data);
+static char *ngx_http_spdy_chunk_size(ngx_conf_t *cf, void *post, void *data);
static ngx_conf_num_bounds_t ngx_http_spdy_headers_comp_bounds = {
@@ -44,6 +47,8 @@ static ngx_conf_post_t ngx_http_spdy_pool_size_post =
{ ngx_http_spdy_pool_size };
static ngx_conf_post_t ngx_http_spdy_streams_index_mask_post =
{ ngx_http_spdy_streams_index_mask };
+static ngx_conf_post_t ngx_http_spdy_chunk_size_post =
+ { ngx_http_spdy_chunk_size };
static ngx_command_t ngx_http_spdy_commands[] = {
@@ -97,6 +102,13 @@ static ngx_command_t ngx_http_spdy_commands[] = {
offsetof(ngx_http_spdy_srv_conf_t, headers_comp),
&ngx_http_spdy_headers_comp_bounds },
+ { ngx_string("spdy_chunk_size"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_size_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_spdy_loc_conf_t, chunk_size),
+ &ngx_http_spdy_chunk_size_post },
+
ngx_null_command
};
@@ -111,8 +123,8 @@ static ngx_http_module_t ngx_http_spdy_module_ctx = {
ngx_http_spdy_create_srv_conf, /* create server configuration */
ngx_http_spdy_merge_srv_conf, /* merge server configuration */
- NULL, /* create location configuration */
- NULL /* merge location configuration */
+ ngx_http_spdy_create_loc_conf, /* create location configuration */
+ ngx_http_spdy_merge_loc_conf /* merge location configuration */
};
@@ -168,11 +180,11 @@ ngx_http_spdy_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
if (r->spdy_stream) {
- v->len = 1;
+ v->len = sizeof("3.1") - 1;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
- v->data = (u_char *) "2";
+ v->data = (u_char *) "3.1";
return NGX_OK;
}
@@ -239,9 +251,7 @@ ngx_http_spdy_init_main_conf(ngx_conf_t *cf, void *conf)
{
ngx_http_spdy_main_conf_t *smcf = conf;
- if (smcf->recv_buffer_size == NGX_CONF_UNSET_SIZE) {
- smcf->recv_buffer_size = 256 * 1024;
- }
+ ngx_conf_init_size_value(smcf->recv_buffer_size, 256 * 1024);
return NGX_CONF_OK;
}
@@ -296,6 +306,34 @@ ngx_http_spdy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
}
+static void *
+ngx_http_spdy_create_loc_conf(ngx_conf_t *cf)
+{
+ ngx_http_spdy_loc_conf_t *slcf;
+
+ slcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_spdy_loc_conf_t));
+ if (slcf == NULL) {
+ return NULL;
+ }
+
+ slcf->chunk_size = NGX_CONF_UNSET_SIZE;
+
+ return slcf;
+}
+
+
+static char *
+ngx_http_spdy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+ ngx_http_spdy_loc_conf_t *prev = parent;
+ ngx_http_spdy_loc_conf_t *conf = child;
+
+ ngx_conf_merge_size_value(conf->chunk_size, prev->chunk_size, 8 * 1024);
+
+ return NGX_CONF_OK;
+}
+
+
static char *
ngx_http_spdy_recv_buffer_size(ngx_conf_t *cf, void *post, void *data)
{
@@ -349,3 +387,22 @@ ngx_http_spdy_streams_index_mask(ngx_conf_t *cf, void *post, void *data)
return NGX_CONF_OK;
}
+
+
+static char *
+ngx_http_spdy_chunk_size(ngx_conf_t *cf, void *post, void *data)
+{
+ size_t *sp = data;
+
+ if (*sp == 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "the spdy chunk size cannot be zero");
+ return NGX_CONF_ERROR;
+ }
+
+ if (*sp > NGX_SPDY_MAX_FRAME_SIZE) {
+ *sp = NGX_SPDY_MAX_FRAME_SIZE;
+ }
+
+ return NGX_CONF_OK;
+}
diff --git a/usr.sbin/nginx/src/http/ngx_http_spdy_module.h b/usr.sbin/nginx/src/http/ngx_http_spdy_module.h
index 97a7a13a6fc..5242322b3d6 100644
--- a/usr.sbin/nginx/src/http/ngx_http_spdy_module.h
+++ b/usr.sbin/nginx/src/http/ngx_http_spdy_module.h
@@ -30,6 +30,11 @@ typedef struct {
} ngx_http_spdy_srv_conf_t;
+typedef struct {
+ size_t chunk_size;
+} ngx_http_spdy_loc_conf_t;
+
+
extern ngx_module_t ngx_http_spdy_module;
diff --git a/usr.sbin/nginx/src/http/ngx_http_special_response.c b/usr.sbin/nginx/src/http/ngx_http_special_response.c
index 875c24d9c75..546400539ba 100644
--- a/usr.sbin/nginx/src/http/ngx_http_special_response.c
+++ b/usr.sbin/nginx/src/http/ngx_http_special_response.c
@@ -370,7 +370,7 @@ ngx_http_special_response_handler(ngx_http_request_t *r, ngx_int_t error)
ngx_http_core_loc_conf_t *clcf;
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "http special response: %d, \"%V?%V\"",
+ "http special response: %i, \"%V?%V\"",
error, &r->uri, &r->args);
r->err_status = error;
diff --git a/usr.sbin/nginx/src/http/ngx_http_upstream.c b/usr.sbin/nginx/src/http/ngx_http_upstream.c
index d99d8545488..040bda10623 100644
--- a/usr.sbin/nginx/src/http/ngx_http_upstream.c
+++ b/usr.sbin/nginx/src/http/ngx_http_upstream.c
@@ -17,6 +17,8 @@ static ngx_int_t ngx_http_upstream_cache_send(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static ngx_int_t ngx_http_upstream_cache_status(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_upstream_cache_last_modified(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data);
#endif
static void ngx_http_upstream_init_request(ngx_http_request_t *r);
@@ -358,6 +360,10 @@ static ngx_http_variable_t ngx_http_upstream_vars[] = {
ngx_http_upstream_cache_status, 0,
NGX_HTTP_VAR_NOCACHEABLE, 0 },
+ { ngx_string("upstream_cache_last_modified"), NULL,
+ ngx_http_upstream_cache_last_modified, 0,
+ NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
+
#endif
{ ngx_null_string, NULL, NULL, 0, 0, 0 }
@@ -369,6 +375,7 @@ static ngx_http_upstream_next_t ngx_http_upstream_next_errors[] = {
{ 502, NGX_HTTP_UPSTREAM_FT_HTTP_502 },
{ 503, NGX_HTTP_UPSTREAM_FT_HTTP_503 },
{ 504, NGX_HTTP_UPSTREAM_FT_HTTP_504 },
+ { 403, NGX_HTTP_UPSTREAM_FT_HTTP_403 },
{ 404, NGX_HTTP_UPSTREAM_FT_HTTP_404 },
{ 0, 0 }
};
@@ -605,7 +612,7 @@ ngx_http_upstream_init_request(ngx_http_request_t *r)
if (uscf->host.len == host->len
&& ((uscf->port == 0 && u->resolved->no_port)
|| uscf->port == u->resolved->port)
- && ngx_memcmp(uscf->host.data, host->data, host->len) == 0)
+ && ngx_strncasecmp(uscf->host.data, host->data, host->len) == 0)
{
goto found;
}
@@ -637,7 +644,6 @@ ngx_http_upstream_init_request(ngx_http_request_t *r)
}
ctx->name = *host;
- ctx->type = NGX_RESOLVE_A;
ctx->handler = ngx_http_upstream_resolve_handler;
ctx->data = r;
ctx->timeout = clcf->resolver_timeout;
@@ -709,7 +715,7 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u)
if (r->cache->header_start + 256 >= u->conf->buffer_size) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"%V_buffer_size %uz is not enough for cache key, "
- "it should increased at least to %uz",
+ "it should be increased to at least %uz",
&u->conf->module, u->conf->buffer_size,
ngx_align(r->cache->header_start + 256, 1024));
@@ -911,16 +917,18 @@ ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx)
#if (NGX_DEBUG)
{
- in_addr_t addr;
+ u_char text[NGX_SOCKADDR_STRLEN];
+ ngx_str_t addr;
ngx_uint_t i;
+ addr.data = text;
+
for (i = 0; i < ctx->naddrs; i++) {
- addr = ntohl(ur->addrs[i]);
+ addr.len = ngx_sock_ntop(ur->addrs[i].sockaddr, ur->addrs[i].socklen,
+ text, NGX_SOCKADDR_STRLEN, 0);
- ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "name was resolved to %ud.%ud.%ud.%ud",
- (addr >> 24) & 0xff, (addr >> 16) & 0xff,
- (addr >> 8) & 0xff, addr & 0xff);
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "name was resolved to %V", &addr);
}
}
#endif
@@ -1069,6 +1077,55 @@ ngx_http_upstream_check_broken_connection(ngx_http_request_t *r,
#endif
+#if (NGX_HAVE_EPOLLRDHUP)
+
+ if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && ev->pending_eof) {
+ socklen_t len;
+
+ ev->eof = 1;
+ c->error = 1;
+
+ err = 0;
+ len = sizeof(ngx_err_t);
+
+ /*
+ * BSDs and Linux return 0 and set a pending error in err
+ * Solaris returns -1 and sets errno
+ */
+
+ if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len)
+ == -1)
+ {
+ err = ngx_socket_errno;
+ }
+
+ if (err) {
+ ev->error = 1;
+ }
+
+ if (!u->cacheable && u->peer.connection) {
+ ngx_log_error(NGX_LOG_INFO, ev->log, err,
+ "epoll_wait() reported that client prematurely closed "
+ "connection, so upstream connection is closed too");
+ ngx_http_upstream_finalize_request(r, u,
+ NGX_HTTP_CLIENT_CLOSED_REQUEST);
+ return;
+ }
+
+ ngx_log_error(NGX_LOG_INFO, ev->log, err,
+ "epoll_wait() reported that client prematurely closed "
+ "connection");
+
+ if (u->peer.connection == NULL) {
+ ngx_http_upstream_finalize_request(r, u,
+ NGX_HTTP_CLIENT_CLOSED_REQUEST);
+ }
+
+ return;
+ }
+
+#endif
+
n = recv(c->fd, buf, 1, MSG_PEEK);
err = ngx_socket_errno;
@@ -1180,7 +1237,7 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u)
return;
}
- /* rc == NGX_OK || rc == NGX_AGAIN */
+ /* rc == NGX_OK || rc == NGX_AGAIN || rc == NGX_DONE */
c = u->peer.connection;
@@ -1281,6 +1338,11 @@ ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r,
{
ngx_int_t rc;
+ if (ngx_http_upstream_test_connect(c) != NGX_OK) {
+ ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
+ return;
+ }
+
if (ngx_ssl_create_connection(u->conf->ssl, c,
NGX_SSL_BUFFER|NGX_SSL_CLIENT)
!= NGX_OK)
@@ -1332,13 +1394,19 @@ ngx_http_upstream_ssl_handshake(ngx_connection_t *c)
c->write->handler = ngx_http_upstream_handler;
c->read->handler = ngx_http_upstream_handler;
+ c = r->connection;
+
ngx_http_upstream_send_request(r, u);
+ ngx_http_run_posted_requests(c);
return;
}
+ c = r->connection;
+
ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
+ ngx_http_run_posted_requests(c);
}
#endif
@@ -1471,22 +1539,10 @@ ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u)
ngx_add_timer(c->read, u->conf->read_timeout);
-#if 1
if (c->read->ready) {
-
- /* post aio operation */
-
- /*
- * TODO comment
- * although we can post aio operation just in the end
- * of ngx_http_upstream_connect() CHECK IT !!!
- * it's better to do here because we postpone header buffer allocation
- */
-
ngx_http_upstream_process_header(r, u);
return;
}
-#endif
u->write_event_handler = ngx_http_upstream_dummy_handler;
@@ -1660,11 +1716,7 @@ ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u)
/* rc == NGX_OK */
- if (u->headers_in.status_n > NGX_HTTP_SPECIAL_RESPONSE) {
-
- if (r->subrequest_in_memory) {
- u->buffer.last = u->buffer.pos;
- }
+ if (u->headers_in.status_n >= NGX_HTTP_SPECIAL_RESPONSE) {
if (ngx_http_upstream_test_next(r, u) == NGX_OK) {
return;
@@ -1693,15 +1745,14 @@ ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u)
}
if (u->input_filter_init(u->input_filter_ctx) == NGX_ERROR) {
- ngx_http_upstream_finalize_request(r, u,
- NGX_HTTP_INTERNAL_SERVER_ERROR);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
n = u->buffer.last - u->buffer.pos;
if (n) {
- u->buffer.last -= n;
+ u->buffer.last = u->buffer.pos;
u->state->response_length += n;
@@ -1709,11 +1760,11 @@ ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u)
ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
+ }
- if (u->length == 0) {
- ngx_http_upstream_finalize_request(r, u, 0);
- return;
- }
+ if (u->length == 0) {
+ ngx_http_upstream_finalize_request(r, u, 0);
+ return;
}
u->read_event_handler = ngx_http_upstream_process_body_in_memory;
@@ -1762,6 +1813,56 @@ ngx_http_upstream_test_next(ngx_http_request_t *r, ngx_http_upstream_t *u)
#endif
}
+#if (NGX_HTTP_CACHE)
+
+ if (status == NGX_HTTP_NOT_MODIFIED
+ && u->cache_status == NGX_HTTP_CACHE_EXPIRED
+ && u->conf->cache_revalidate)
+ {
+ time_t now, valid;
+ ngx_int_t rc;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http upstream not modified");
+
+ now = ngx_time();
+ valid = r->cache->valid_sec;
+
+ rc = u->reinit_request(r);
+
+ if (rc != NGX_OK) {
+ ngx_http_upstream_finalize_request(r, u, rc);
+ return NGX_OK;
+ }
+
+ u->cache_status = NGX_HTTP_CACHE_REVALIDATED;
+ rc = ngx_http_upstream_cache_send(r, u);
+
+ if (valid == 0) {
+ valid = r->cache->valid_sec;
+ }
+
+ if (valid == 0) {
+ valid = ngx_http_file_cache_valid(u->conf->cache_valid,
+ u->headers_in.status_n);
+ if (valid) {
+ valid = now + valid;
+ }
+ }
+
+ if (valid) {
+ r->cache->valid_sec = valid;
+ r->cache->date = now;
+
+ ngx_http_file_cache_update_header(r);
+ }
+
+ ngx_http_upstream_finalize_request(r, u, rc);
+ return NGX_OK;
+ }
+
+#endif
+
return NGX_DECLINED;
}
@@ -1876,7 +1977,7 @@ ngx_http_upstream_test_connect(ngx_connection_t *c)
if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len)
== -1)
{
- err = ngx_errno;
+ err = ngx_socket_errno;
}
if (err) {
@@ -1893,7 +1994,7 @@ ngx_http_upstream_test_connect(ngx_connection_t *c)
static ngx_int_t
ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u)
{
- ngx_str_t *uri, args;
+ ngx_str_t uri, args;
ngx_uint_t i, flags;
ngx_list_part_t *part;
ngx_table_elt_t *h;
@@ -1934,11 +2035,11 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u)
}
}
- uri = &u->headers_in.x_accel_redirect->value;
+ uri = u->headers_in.x_accel_redirect->value;
ngx_str_null(&args);
flags = NGX_HTTP_LOG_UNSAFE;
- if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) {
+ if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) {
ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND);
return NGX_DONE;
}
@@ -1947,7 +2048,7 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u)
r->method = NGX_HTTP_GET;
}
- ngx_http_internal_redirect(r, uri, &args);
+ ngx_http_internal_redirect(r, &uri, &args);
ngx_http_finalize_request(r, NGX_DONE);
return NGX_DONE;
}
@@ -2006,7 +2107,7 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u)
r->headers_out.content_length_n = u->headers_in.content_length_n;
- u->length = u->headers_in.content_length_n;
+ u->length = -1;
return NGX_OK;
}
@@ -2030,7 +2131,7 @@ ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r,
if (rev->timedout) {
ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
- ngx_http_upstream_finalize_request(r, u, NGX_ETIMEDOUT);
+ ngx_http_upstream_finalize_request(r, u, NGX_HTTP_GATEWAY_TIME_OUT);
return;
}
@@ -2106,6 +2207,8 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
return;
}
+ u->header_sent = 1;
+
if (u->upgrade) {
ngx_http_upstream_upgrade(r, u);
return;
@@ -2132,8 +2235,6 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
}
}
- u->header_sent = 1;
-
if (r->request_body && r->request_body->temp_file) {
ngx_pool_run_cleanup_file(r->pool, r->request_body->temp_file->file.fd);
r->request_body->temp_file->file.fd = NGX_INVALID_FILE;
@@ -2156,7 +2257,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
r->limit_rate = 0;
if (u->input_filter_init(u->input_filter_ctx) == NGX_ERROR) {
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
@@ -2170,7 +2271,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
{
ngx_connection_error(c, ngx_socket_errno,
"setsockopt(TCP_NODELAY) failed");
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
@@ -2185,7 +2286,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
u->state->response_length += n;
if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
@@ -2196,7 +2297,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
u->buffer.last = u->buffer.start;
if (ngx_http_send_special(r, NGX_HTTP_FLUSH) == NGX_ERROR) {
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
@@ -2220,7 +2321,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
switch (ngx_http_test_predicates(r, u->conf->no_cache)) {
case NGX_ERROR:
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
case NGX_DECLINED:
@@ -2236,7 +2337,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
r->cache->file_cache = u->conf->cache->data;
if (ngx_http_file_cache_create(r) != NGX_OK) {
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
}
@@ -2297,7 +2398,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
p->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
if (p->temp_file == NULL) {
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
@@ -2320,7 +2421,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
p->preread_bufs = ngx_alloc_chain_link(r->pool);
if (p->preread_bufs == NULL) {
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
@@ -2334,7 +2435,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
p->buf_to_file = ngx_calloc_buf(r->pool);
if (p->buf_to_file == NULL) {
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
@@ -2382,7 +2483,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
if (u->input_filter_init
&& u->input_filter_init(p->input_ctx) != NGX_OK)
{
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
@@ -2424,7 +2525,7 @@ ngx_http_upstream_upgrade(ngx_http_request_t *r, ngx_http_upstream_t *u)
{
ngx_connection_error(c, ngx_socket_errno,
"setsockopt(TCP_NODELAY) failed");
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
@@ -2440,7 +2541,7 @@ ngx_http_upstream_upgrade(ngx_http_request_t *r, ngx_http_upstream_t *u)
{
ngx_connection_error(u->peer.connection, ngx_socket_errno,
"setsockopt(TCP_NODELAY) failed");
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
@@ -2449,7 +2550,7 @@ ngx_http_upstream_upgrade(ngx_http_request_t *r, ngx_http_upstream_t *u)
}
if (ngx_http_send_special(r, NGX_HTTP_FLUSH) == NGX_ERROR) {
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
@@ -2524,7 +2625,7 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r,
if (upstream->read->timedout || upstream->write->timedout) {
ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_HTTP_GATEWAY_TIME_OUT);
return;
}
@@ -2547,7 +2648,7 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r,
if (b->start == NULL) {
b->start = ngx_palloc(r->pool, u->conf->buffer_size);
if (b->start == NULL) {
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
@@ -2570,7 +2671,7 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r,
n = dst->send(dst, b->pos, size);
if (n == NGX_ERROR) {
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
@@ -2625,7 +2726,7 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r,
if (ngx_handle_write_event(upstream->write, u->conf->send_lowat)
!= NGX_OK)
{
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
@@ -2637,7 +2738,7 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r,
}
if (ngx_handle_read_event(upstream->read, 0) != NGX_OK) {
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
@@ -2651,12 +2752,12 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r,
if (ngx_handle_write_event(downstream->write, clcf->send_lowat)
!= NGX_OK)
{
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
if (ngx_handle_read_event(downstream->read, 0) != NGX_OK) {
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
@@ -2711,7 +2812,7 @@ ngx_http_upstream_process_non_buffered_upstream(ngx_http_request_t *r,
if (c->read->timedout) {
ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_HTTP_GATEWAY_TIME_OUT);
return;
}
@@ -2747,7 +2848,7 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
rc = ngx_http_output_filter(r, u->out_bufs);
if (rc == NGX_ERROR) {
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
@@ -2758,13 +2859,27 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
if (u->busy_bufs == NULL) {
if (u->length == 0
- || upstream->read->eof
- || upstream->read->error)
+ || (upstream->read->eof && u->length == -1))
{
ngx_http_upstream_finalize_request(r, u, 0);
return;
}
+ if (upstream->read->eof) {
+ ngx_log_error(NGX_LOG_ERR, upstream->log, 0,
+ "upstream prematurely closed connection");
+
+ ngx_http_upstream_finalize_request(r, u,
+ NGX_HTTP_BAD_GATEWAY);
+ return;
+ }
+
+ if (upstream->read->error) {
+ ngx_http_upstream_finalize_request(r, u,
+ NGX_HTTP_BAD_GATEWAY);
+ return;
+ }
+
b->pos = b->start;
b->last = b->start;
}
@@ -2784,7 +2899,7 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
u->state->response_length += n;
if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
}
@@ -2803,7 +2918,7 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
if (ngx_handle_write_event(downstream->write, clcf->send_lowat)
!= NGX_OK)
{
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
}
@@ -2816,7 +2931,7 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
}
if (ngx_handle_read_event(upstream->read, 0) != NGX_OK) {
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
@@ -2907,14 +3022,14 @@ ngx_http_upstream_process_downstream(ngx_http_request_t *r)
ngx_add_timer(wev, p->send_timeout);
if (ngx_handle_write_event(wev, p->send_lowat) != NGX_OK) {
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
}
return;
}
if (ngx_event_pipe(p, wev->write) == NGX_ABORT) {
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
@@ -2932,14 +3047,14 @@ ngx_http_upstream_process_downstream(ngx_http_request_t *r)
"http downstream delayed");
if (ngx_handle_write_event(wev, p->send_lowat) != NGX_OK) {
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
}
return;
}
if (ngx_event_pipe(p, 1) == NGX_ABORT) {
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
}
@@ -2967,7 +3082,7 @@ ngx_http_upstream_process_upstream(ngx_http_request_t *r,
} else {
if (ngx_event_pipe(u->pipe, 0) == NGX_ABORT) {
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
}
@@ -2992,11 +3107,12 @@ ngx_http_upstream_process_request(ngx_http_request_t *r)
if (p->upstream_eof || p->upstream_done) {
- tf = u->pipe->temp_file;
+ tf = p->temp_file;
if (u->headers_in.status_n == NGX_HTTP_OK
+ && (p->upstream_done || p->length == -1)
&& (u->headers_in.content_length_n == -1
- || (u->headers_in.content_length_n == tf->offset)))
+ || u->headers_in.content_length_n == tf->offset))
{
ngx_http_upstream_store(r, u);
u->store = 0;
@@ -3009,15 +3125,16 @@ ngx_http_upstream_process_request(ngx_http_request_t *r)
if (u->cacheable) {
if (p->upstream_done) {
- ngx_http_file_cache_update(r, u->pipe->temp_file);
+ ngx_http_file_cache_update(r, p->temp_file);
} else if (p->upstream_eof) {
- tf = u->pipe->temp_file;
+ tf = p->temp_file;
- if (u->headers_in.content_length_n == -1
- || u->headers_in.content_length_n
- == tf->offset - (off_t) r->cache->body_start)
+ if (p->length == -1
+ && (u->headers_in.content_length_n == -1
+ || u->headers_in.content_length_n
+ == tf->offset - (off_t) r->cache->body_start))
{
ngx_http_file_cache_update(r, tf);
@@ -3026,7 +3143,7 @@ ngx_http_upstream_process_request(ngx_http_request_t *r)
}
} else if (p->upstream_error) {
- ngx_http_file_cache_free(r->cache, u->pipe->temp_file);
+ ngx_http_file_cache_free(r->cache, p->temp_file);
}
}
@@ -3035,10 +3152,20 @@ ngx_http_upstream_process_request(ngx_http_request_t *r)
if (p->upstream_done || p->upstream_eof || p->upstream_error) {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http upstream exit: %p", p->out);
-#if 0
- ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
-#endif
- ngx_http_upstream_finalize_request(r, u, 0);
+
+ if (p->upstream_done
+ || (p->upstream_eof && p->length == -1))
+ {
+ ngx_http_upstream_finalize_request(r, u, 0);
+ return;
+ }
+
+ if (p->upstream_eof) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "upstream prematurely closed connection");
+ }
+
+ ngx_http_upstream_finalize_request(r, u, NGX_HTTP_BAD_GATEWAY);
return;
}
}
@@ -3048,7 +3175,7 @@ ngx_http_upstream_process_request(ngx_http_request_t *r)
"http upstream downstream error");
if (!u->cacheable && !u->store && u->peer.connection) {
- ngx_http_upstream_finalize_request(r, u, 0);
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
}
}
}
@@ -3148,14 +3275,13 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u,
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http next upstream, %xi", ft_type);
-#if 0
- ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
-#endif
-
if (u->peer.sockaddr) {
- if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404) {
+ if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_403
+ || ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404)
+ {
state = NGX_PEER_NEXT;
+
} else {
state = NGX_PEER_FAILED;
}
@@ -3187,6 +3313,10 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u,
status = NGX_HTTP_INTERNAL_SERVER_ERROR;
break;
+ case NGX_HTTP_UPSTREAM_FT_HTTP_403:
+ status = NGX_HTTP_FORBIDDEN;
+ break;
+
case NGX_HTTP_UPSTREAM_FT_HTTP_404:
status = NGX_HTTP_NOT_FOUND;
break;
@@ -3258,13 +3388,6 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u,
u->peer.connection = NULL;
}
-#if 0
- if (u->conf->busy_lock && !u->busy_locked) {
- ngx_http_upstream_busy_lock(p);
- return;
- }
-#endif
-
ngx_http_upstream_connect(r, u);
}
@@ -3285,6 +3408,7 @@ static void
ngx_http_upstream_finalize_request(ngx_http_request_t *r,
ngx_http_upstream_t *u, ngx_int_t rc)
{
+ ngx_uint_t flush;
ngx_time_t *tp;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -3391,11 +3515,10 @@ ngx_http_upstream_finalize_request(ngx_http_request_t *r,
#endif
- if (u->header_sent
- && rc != NGX_HTTP_REQUEST_TIME_OUT
- && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE))
+ if (r->subrequest_in_memory
+ && u->headers_in.status_n >= NGX_HTTP_SPECIAL_RESPONSE)
{
- rc = 0;
+ u->buffer.last = u->buffer.pos;
}
if (rc == NGX_DECLINED) {
@@ -3404,14 +3527,32 @@ ngx_http_upstream_finalize_request(ngx_http_request_t *r,
r->connection->log->action = "sending to client";
- if (rc == 0
- && !r->header_only
-#if (NGX_HTTP_CACHE)
- && !r->cached
-#endif
- )
+ if (!u->header_sent
+ || rc == NGX_HTTP_REQUEST_TIME_OUT
+ || rc == NGX_HTTP_CLIENT_CLOSED_REQUEST)
{
+ ngx_http_finalize_request(r, rc);
+ return;
+ }
+
+ flush = 0;
+
+ if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
+ rc = NGX_ERROR;
+ flush = 1;
+ }
+
+ if (r->header_only) {
+ ngx_http_finalize_request(r, rc);
+ return;
+ }
+
+ if (rc == 0) {
rc = ngx_http_send_special(r, NGX_HTTP_LAST);
+
+ } else if (flush) {
+ r->keepalive = 0;
+ rc = ngx_http_send_special(r, NGX_HTTP_FLUSH);
}
ngx_http_finalize_request(r, rc);
@@ -3513,7 +3654,7 @@ ngx_http_upstream_process_cache_control(ngx_http_request_t *r,
return NGX_OK;
}
- if (r->cache->valid_sec != 0) {
+ if (r->cache->valid_sec != 0 && u->headers_in.x_accel_expires != NULL) {
return NGX_OK;
}
@@ -4042,7 +4183,12 @@ ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r,
if (r->cached) {
r->allow_ranges = 1;
return NGX_OK;
+ }
+ if (r->upstream->cacheable) {
+ r->allow_ranges = 1;
+ r->single_range = 1;
+ return NGX_OK;
}
#endif
@@ -4274,7 +4420,7 @@ ngx_http_upstream_response_time_variable(ngx_http_request_t *r,
ms = (ngx_msec_int_t)
(state[i].response_sec * 1000 + state[i].response_msec);
ms = ngx_max(ms, 0);
- p = ngx_sprintf(p, "%d.%03d", ms / 1000, ms % 1000);
+ p = ngx_sprintf(p, "%T.%03M", (time_t) ms / 1000, ms % 1000);
} else {
*p++ = '-';
@@ -4406,6 +4552,36 @@ ngx_http_upstream_cache_status(ngx_http_request_t *r,
return NGX_OK;
}
+
+static ngx_int_t
+ngx_http_upstream_cache_last_modified(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data)
+{
+ u_char *p;
+
+ if (r->upstream == NULL
+ || !r->upstream->conf->cache_revalidate
+ || r->upstream->cache_status != NGX_HTTP_CACHE_EXPIRED
+ || r->cache->last_modified == -1)
+ {
+ v->not_found = 1;
+ return NGX_OK;
+ }
+
+ p = ngx_pnalloc(r->pool, sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1);
+ if (p == NULL) {
+ return NGX_ERROR;
+ }
+
+ v->len = ngx_http_time(p, r->cache->last_modified) - p;
+ v->valid = 1;
+ v->no_cacheable = 0;
+ v->not_found = 0;
+ v->data = p;
+
+ return NGX_OK;
+}
+
#endif
@@ -4615,7 +4791,7 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
continue;
}
- if (ngx_strncmp(value[i].data, "backup", 6) == 0) {
+ if (ngx_strcmp(value[i].data, "backup") == 0) {
if (!(uscf->flags & NGX_HTTP_UPSTREAM_BACKUP)) {
goto invalid;
@@ -4626,7 +4802,7 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
continue;
}
- if (ngx_strncmp(value[i].data, "down", 4) == 0) {
+ if (ngx_strcmp(value[i].data, "down") == 0) {
if (!(uscf->flags & NGX_HTTP_UPSTREAM_DOWN)) {
goto invalid;
diff --git a/usr.sbin/nginx/src/http/ngx_http_upstream.h b/usr.sbin/nginx/src/http/ngx_http_upstream.h
index 29ebf9bd92d..9f96c50f309 100644
--- a/usr.sbin/nginx/src/http/ngx_http_upstream.h
+++ b/usr.sbin/nginx/src/http/ngx_http_upstream.h
@@ -24,10 +24,11 @@
#define NGX_HTTP_UPSTREAM_FT_HTTP_502 0x00000020
#define NGX_HTTP_UPSTREAM_FT_HTTP_503 0x00000040
#define NGX_HTTP_UPSTREAM_FT_HTTP_504 0x00000080
-#define NGX_HTTP_UPSTREAM_FT_HTTP_404 0x00000100
-#define NGX_HTTP_UPSTREAM_FT_UPDATING 0x00000200
-#define NGX_HTTP_UPSTREAM_FT_BUSY_LOCK 0x00000400
-#define NGX_HTTP_UPSTREAM_FT_MAX_WAITING 0x00000800
+#define NGX_HTTP_UPSTREAM_FT_HTTP_403 0x00000100
+#define NGX_HTTP_UPSTREAM_FT_HTTP_404 0x00000200
+#define NGX_HTTP_UPSTREAM_FT_UPDATING 0x00000400
+#define NGX_HTTP_UPSTREAM_FT_BUSY_LOCK 0x00000800
+#define NGX_HTTP_UPSTREAM_FT_MAX_WAITING 0x00001000
#define NGX_HTTP_UPSTREAM_FT_NOLIVE 0x40000000
#define NGX_HTTP_UPSTREAM_FT_OFF 0x80000000
@@ -35,6 +36,7 @@
|NGX_HTTP_UPSTREAM_FT_HTTP_502 \
|NGX_HTTP_UPSTREAM_FT_HTTP_503 \
|NGX_HTTP_UPSTREAM_FT_HTTP_504 \
+ |NGX_HTTP_UPSTREAM_FT_HTTP_403 \
|NGX_HTTP_UPSTREAM_FT_HTTP_404)
#define NGX_HTTP_UPSTREAM_INVALID_HEADER 40
@@ -176,6 +178,8 @@ typedef struct {
ngx_flag_t cache_lock;
ngx_msec_t cache_lock_timeout;
+ ngx_flag_t cache_revalidate;
+
ngx_array_t *cache_valid;
ngx_array_t *cache_bypass;
ngx_array_t *no_cache;
@@ -252,7 +256,7 @@ typedef struct {
ngx_uint_t no_port; /* unsigned no_port:1 */
ngx_uint_t naddrs;
- in_addr_t *addrs;
+ ngx_addr_t *addrs;
struct sockaddr *sockaddr;
socklen_t socklen;
diff --git a/usr.sbin/nginx/src/http/ngx_http_upstream_round_robin.c b/usr.sbin/nginx/src/http/ngx_http_upstream_round_robin.c
index e0c6c58c747..85ff5581baf 100644
--- a/usr.sbin/nginx/src/http/ngx_http_upstream_round_robin.c
+++ b/usr.sbin/nginx/src/http/ngx_http_upstream_round_robin.c
@@ -71,20 +71,20 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
n = 0;
for (i = 0; i < us->servers->nelts; i++) {
- for (j = 0; j < server[i].naddrs; j++) {
- if (server[i].backup) {
- continue;
- }
+ if (server[i].backup) {
+ continue;
+ }
+ for (j = 0; j < server[i].naddrs; j++) {
peers->peer[n].sockaddr = server[i].addrs[j].sockaddr;
peers->peer[n].socklen = server[i].addrs[j].socklen;
peers->peer[n].name = server[i].addrs[j].name;
- peers->peer[n].max_fails = server[i].max_fails;
- peers->peer[n].fail_timeout = server[i].fail_timeout;
- peers->peer[n].down = server[i].down;
peers->peer[n].weight = server[i].weight;
peers->peer[n].effective_weight = server[i].weight;
peers->peer[n].current_weight = 0;
+ peers->peer[n].max_fails = server[i].max_fails;
+ peers->peer[n].fail_timeout = server[i].fail_timeout;
+ peers->peer[n].down = server[i].down;
n++;
}
}
@@ -125,11 +125,11 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
n = 0;
for (i = 0; i < us->servers->nelts; i++) {
- for (j = 0; j < server[i].naddrs; j++) {
- if (!server[i].backup) {
- continue;
- }
+ if (!server[i].backup) {
+ continue;
+ }
+ for (j = 0; j < server[i].naddrs; j++) {
backup->peer[n].sockaddr = server[i].addrs[j].sockaddr;
backup->peer[n].socklen = server[i].addrs[j].socklen;
backup->peer[n].name = server[i].addrs[j].name;
@@ -266,8 +266,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
{
u_char *p;
size_t len;
+ socklen_t socklen;
ngx_uint_t i, n;
- struct sockaddr_in *sin;
+ struct sockaddr *sockaddr;
ngx_http_upstream_rr_peers_t *peers;
ngx_http_upstream_rr_peer_data_t *rrp;
@@ -306,27 +307,34 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
for (i = 0; i < ur->naddrs; i++) {
- len = NGX_INET_ADDRSTRLEN + sizeof(":65536") - 1;
+ socklen = ur->addrs[i].socklen;
- p = ngx_pnalloc(r->pool, len);
- if (p == NULL) {
+ sockaddr = ngx_palloc(r->pool, socklen);
+ if (sockaddr == NULL) {
return NGX_ERROR;
}
- len = ngx_inet_ntop(AF_INET, &ur->addrs[i], p, NGX_INET_ADDRSTRLEN);
- len = ngx_sprintf(&p[len], ":%d", ur->port) - p;
+ ngx_memcpy(sockaddr, ur->addrs[i].sockaddr, socklen);
- sin = ngx_pcalloc(r->pool, sizeof(struct sockaddr_in));
- if (sin == NULL) {
+ switch (sockaddr->sa_family) {
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ ((struct sockaddr_in6 *) sockaddr)->sin6_port = htons(ur->port);
+ break;
+#endif
+ default: /* AF_INET */
+ ((struct sockaddr_in *) sockaddr)->sin_port = htons(ur->port);
+ }
+
+ p = ngx_pnalloc(r->pool, NGX_SOCKADDR_STRLEN);
+ if (p == NULL) {
return NGX_ERROR;
}
- sin->sin_family = AF_INET;
- sin->sin_port = htons(ur->port);
- sin->sin_addr.s_addr = ur->addrs[i];
+ len = ngx_sock_ntop(sockaddr, socklen, p, NGX_SOCKADDR_STRLEN, 1);
- peers->peer[i].sockaddr = (struct sockaddr *) sin;
- peers->peer[i].socklen = sizeof(struct sockaddr_in);
+ peers->peer[i].sockaddr = sockaddr;
+ peers->peer[i].socklen = socklen;
peers->peer[i].name.len = len;
peers->peer[i].name.data = p;
peers->peer[i].weight = 1;
diff --git a/usr.sbin/nginx/src/http/ngx_http_variables.c b/usr.sbin/nginx/src/http/ngx_http_variables.c
index 7a7d15c1e0d..f618622976f 100644
--- a/usr.sbin/nginx/src/http/ngx_http_variables.c
+++ b/usr.sbin/nginx/src/http/ngx_http_variables.c
@@ -54,6 +54,8 @@ static ngx_int_t ngx_http_variable_remote_addr(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_remote_port(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_variable_proxy_protocol_addr(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_server_addr(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_server_port(ngx_http_request_t *r,
@@ -183,6 +185,9 @@ static ngx_http_variable_t ngx_http_core_variables[] = {
{ ngx_string("remote_port"), NULL, ngx_http_variable_remote_port, 0, 0, 0 },
+ { ngx_string("proxy_protocol_addr"), NULL,
+ ngx_http_variable_proxy_protocol_addr, 0, 0, 0 },
+
{ ngx_string("server_addr"), NULL, ngx_http_variable_server_addr, 0, 0, 0 },
{ ngx_string("server_port"), NULL, ngx_http_variable_server_port, 0, 0, 0 },
@@ -487,7 +492,7 @@ ngx_http_get_indexed_variable(ngx_http_request_t *r, ngx_uint_t index)
if (cmcf->variables.nelts <= index) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
- "unknown variable index: %d", index);
+ "unknown variable index: %ui", index);
return NULL;
}
@@ -1185,6 +1190,12 @@ ngx_http_variable_remote_port(ngx_http_request_t *r,
break;
#endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+ case AF_UNIX:
+ port = 0;
+ break;
+#endif
+
default: /* AF_INET */
sin = (struct sockaddr_in *) r->connection->sockaddr;
port = ntohs(sin->sin_port);
@@ -1200,6 +1211,20 @@ ngx_http_variable_remote_port(ngx_http_request_t *r,
static ngx_int_t
+ngx_http_variable_proxy_protocol_addr(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data)
+{
+ v->len = r->connection->proxy_protocol_addr.len;
+ v->valid = 1;
+ v->no_cacheable = 0;
+ v->not_found = 0;
+ v->data = r->connection->proxy_protocol_addr.data;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
ngx_http_variable_server_addr(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
@@ -1263,6 +1288,12 @@ ngx_http_variable_server_port(ngx_http_request_t *r,
break;
#endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+ case AF_UNIX:
+ port = 0;
+ break;
+#endif
+
default: /* AF_INET */
sin = (struct sockaddr_in *) r->connection->local_sockaddr;
port = ntohs(sin->sin_port);
@@ -1374,7 +1405,9 @@ ngx_http_variable_document_root(ngx_http_request_t *r,
return NGX_ERROR;
}
- if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &path, 0) != NGX_OK) {
+ if (ngx_get_full_name(r->pool, (ngx_str_t *) &ngx_cycle->prefix, &path)
+ != NGX_OK)
+ {
return NGX_ERROR;
}
@@ -1416,7 +1449,9 @@ ngx_http_variable_realpath_root(ngx_http_request_t *r,
path.data[path.len - 1] = '\0';
- if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &path, 0) != NGX_OK) {
+ if (ngx_get_full_name(r->pool, (ngx_str_t *) &ngx_cycle->prefix, &path)
+ != NGX_OK)
+ {
return NGX_ERROR;
}
}
@@ -1740,8 +1775,7 @@ ngx_http_variable_sent_last_modified(ngx_http_request_t *r,
}
if (r->headers_out.last_modified_time >= 0) {
- p = ngx_pnalloc(r->pool,
- sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT") - 1);
+ p = ngx_pnalloc(r->pool, sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1);
if (p == NULL) {
return NGX_ERROR;
}
@@ -2257,6 +2291,7 @@ ngx_http_regex_compile(ngx_conf_t *cf, ngx_regex_compile_t *rc)
re->regex = rc->regex;
re->ncaptures = rc->captures;
+ re->name = rc->pattern;
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
cmcf->ncaptures = ngx_max(cmcf->ncaptures, re->ncaptures);
@@ -2274,7 +2309,6 @@ ngx_http_regex_compile(ngx_conf_t *cf, ngx_regex_compile_t *rc)
re->variables = rv;
re->nvariables = n;
- re->name = rc->pattern;
size = rc->name_size;
p = rc->names;
diff --git a/usr.sbin/nginx/src/http/ngx_http_write_filter_module.c b/usr.sbin/nginx/src/http/ngx_http_write_filter_module.c
index 5594c7faaad..83cb1fa1e98 100644
--- a/usr.sbin/nginx/src/http/ngx_http_write_filter_module.c
+++ b/usr.sbin/nginx/src/http/ngx_http_write_filter_module.c
@@ -184,7 +184,10 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in)
return NGX_AGAIN;
}
- if (size == 0 && !(c->buffered & NGX_LOWLEVEL_BUFFERED)) {
+ if (size == 0
+ && !(c->buffered & NGX_LOWLEVEL_BUFFERED)
+ && !(last && c->need_last_buf))
+ {
if (last || flush) {
for (cl = r->out; cl; /* void */) {
ln = cl;
@@ -207,8 +210,12 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in)
}
if (r->limit_rate) {
+ if (r->limit_rate_after == 0) {
+ r->limit_rate_after = clcf->limit_rate_after;
+ }
+
limit = (off_t) r->limit_rate * (ngx_time() - r->start_sec + 1)
- - (c->sent - clcf->limit_rate_after);
+ - (c->sent - r->limit_rate_after);
if (limit <= 0) {
c->write->delayed = 1;
@@ -249,14 +256,14 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in)
nsent = c->sent;
- if (clcf->limit_rate_after) {
+ if (r->limit_rate_after) {
- sent -= clcf->limit_rate_after;
+ sent -= r->limit_rate_after;
if (sent < 0) {
sent = 0;
}
- nsent -= clcf->limit_rate_after;
+ nsent -= r->limit_rate_after;
if (nsent < 0) {
nsent = 0;
}
diff --git a/usr.sbin/nginx/src/mail/ngx_mail.c b/usr.sbin/nginx/src/mail/ngx_mail.c
index 3812e15179e..350d2cdf90b 100644
--- a/usr.sbin/nginx/src/mail/ngx_mail.c
+++ b/usr.sbin/nginx/src/mail/ngx_mail.c
@@ -465,7 +465,8 @@ ngx_mail_add_addrs(ngx_conf_t *cf, ngx_mail_port_t *mport,
addrs[i].conf.ssl = addr[i].ssl;
#endif
- len = ngx_sock_ntop(addr[i].sockaddr, buf, NGX_SOCKADDR_STRLEN, 1);
+ len = ngx_sock_ntop(addr[i].sockaddr, addr[i].socklen, buf,
+ NGX_SOCKADDR_STRLEN, 1);
p = ngx_pnalloc(cf->pool, len);
if (p == NULL) {
@@ -513,7 +514,8 @@ ngx_mail_add_addrs6(ngx_conf_t *cf, ngx_mail_port_t *mport,
addrs6[i].conf.ssl = addr[i].ssl;
#endif
- len = ngx_sock_ntop(addr[i].sockaddr, buf, NGX_SOCKADDR_STRLEN, 1);
+ len = ngx_sock_ntop(addr[i].sockaddr, addr[i].socklen, buf,
+ NGX_SOCKADDR_STRLEN, 1);
p = ngx_pnalloc(cf->pool, len);
if (p == NULL) {
diff --git a/usr.sbin/nginx/src/mail/ngx_mail.h b/usr.sbin/nginx/src/mail/ngx_mail.h
index ccdfb8c6f10..dc39f1e1375 100644
--- a/usr.sbin/nginx/src/mail/ngx_mail.h
+++ b/usr.sbin/nginx/src/mail/ngx_mail.h
@@ -234,6 +234,8 @@ typedef struct {
ngx_str_t smtp_from;
ngx_str_t smtp_to;
+ ngx_str_t cmd;
+
ngx_uint_t command;
ngx_array_t args;
diff --git a/usr.sbin/nginx/src/mail/ngx_mail_auth_http_module.c b/usr.sbin/nginx/src/mail/ngx_mail_auth_http_module.c
index 2e9b9f24da8..8094bbc5cc7 100644
--- a/usr.sbin/nginx/src/mail/ngx_mail_auth_http_module.c
+++ b/usr.sbin/nginx/src/mail/ngx_mail_auth_http_module.c
@@ -699,7 +699,6 @@ ngx_mail_auth_http_process_headers(ngx_mail_session_t *s,
p = ngx_pnalloc(s->connection->pool, ctx->err.len);
if (p == NULL) {
- ngx_close_connection(ctx->peer.connection);
ngx_destroy_pool(ctx->pool);
ngx_mail_session_internal_server_error(s);
return;
diff --git a/usr.sbin/nginx/src/mail/ngx_mail_core_module.c b/usr.sbin/nginx/src/mail/ngx_mail_core_module.c
index be8673c299f..4ee7c8dc3d7 100644
--- a/usr.sbin/nginx/src/mail/ngx_mail_core_module.c
+++ b/usr.sbin/nginx/src/mail/ngx_mail_core_module.c
@@ -439,7 +439,8 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ls->bind = 1;
} else {
- len = ngx_sock_ntop(sa, buf, NGX_SOCKADDR_STRLEN, 1);
+ len = ngx_sock_ntop(sa, ls->socklen, buf,
+ NGX_SOCKADDR_STRLEN, 1);
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"ipv6only is not supported "
diff --git a/usr.sbin/nginx/src/mail/ngx_mail_handler.c b/usr.sbin/nginx/src/mail/ngx_mail_handler.c
index ae955f9c6ae..47ddb0dcf05 100644
--- a/usr.sbin/nginx/src/mail/ngx_mail_handler.c
+++ b/usr.sbin/nginx/src/mail/ngx_mail_handler.c
@@ -127,7 +127,7 @@ ngx_mail_init_connection(ngx_connection_t *c)
c->data = s;
s->connection = c;
- ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%ui client %V connected to %V",
+ ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%uA client %V connected to %V",
c->number, &c->addr_text, s->addr_text);
ctx = ngx_palloc(c->pool, sizeof(ngx_mail_log_ctx_t));
@@ -559,8 +559,13 @@ ngx_mail_send(ngx_event_t *wev)
n = c->send(c, s->out.data, s->out.len);
if (n > 0) {
+ s->out.data += n;
s->out.len -= n;
+ if (s->out.len != 0) {
+ goto again;
+ }
+
if (wev->timer_set) {
ngx_del_timer(wev);
}
@@ -584,6 +589,8 @@ ngx_mail_send(ngx_event_t *wev)
/* n == NGX_AGAIN */
+again:
+
cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
ngx_add_timer(c->write, cscf->timeout);
@@ -620,7 +627,9 @@ ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c)
return NGX_ERROR;
}
- return NGX_AGAIN;
+ if (s->buffer->pos == s->buffer->last) {
+ return NGX_AGAIN;
+ }
}
cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
@@ -661,8 +670,12 @@ void
ngx_mail_auth(ngx_mail_session_t *s, ngx_connection_t *c)
{
s->args.nelts = 0;
- s->buffer->pos = s->buffer->start;
- s->buffer->last = s->buffer->start;
+
+ if (s->buffer->pos == s->buffer->last) {
+ s->buffer->pos = s->buffer->start;
+ s->buffer->last = s->buffer->start;
+ }
+
s->state = 0;
if (c->read->timer_set) {
diff --git a/usr.sbin/nginx/src/mail/ngx_mail_parse.c b/usr.sbin/nginx/src/mail/ngx_mail_parse.c
index eb16d5b4fe9..b158f5a0fba 100644
--- a/usr.sbin/nginx/src/mail/ngx_mail_parse.c
+++ b/usr.sbin/nginx/src/mail/ngx_mail_parse.c
@@ -626,6 +626,8 @@ ngx_mail_smtp_parse_command(ngx_mail_session_t *s)
ngx_str_t *arg;
enum {
sw_start = 0,
+ sw_command,
+ sw_invalid,
sw_spaces_before_argument,
sw_argument,
sw_almost_done
@@ -640,8 +642,14 @@ ngx_mail_smtp_parse_command(ngx_mail_session_t *s)
/* SMTP command */
case sw_start:
+ s->cmd_start = p;
+ state = sw_command;
+
+ /* fall through */
+
+ case sw_command:
if (ch == ' ' || ch == CR || ch == LF) {
- c = s->buffer->start;
+ c = s->cmd_start;
if (p - c == 4) {
@@ -719,6 +727,9 @@ ngx_mail_smtp_parse_command(ngx_mail_session_t *s)
goto invalid;
}
+ s->cmd.data = s->cmd_start;
+ s->cmd.len = p - s->cmd_start;
+
switch (ch) {
case ' ':
state = sw_spaces_before_argument;
@@ -738,6 +749,9 @@ ngx_mail_smtp_parse_command(ngx_mail_session_t *s)
break;
+ case sw_invalid:
+ goto invalid;
+
case sw_spaces_before_argument:
switch (ch) {
case ' ':
@@ -824,9 +838,21 @@ done:
invalid:
- s->state = sw_start;
+ s->state = sw_invalid;
s->arg_start = NULL;
+ /* skip invalid command till LF */
+
+ for (p = s->buffer->pos; p < s->buffer->last; p++) {
+ if (*p == LF) {
+ s->state = sw_start;
+ p++;
+ break;
+ }
+ }
+
+ s->buffer->pos = p;
+
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
@@ -842,6 +868,10 @@ ngx_mail_auth_parse(ngx_mail_session_t *s, ngx_connection_t *c)
}
#endif
+ if (s->args.nelts == 0) {
+ return NGX_MAIL_PARSE_INVALID_COMMAND;
+ }
+
arg = s->args.elts;
if (arg[0].len == 5) {
diff --git a/usr.sbin/nginx/src/mail/ngx_mail_proxy_module.c b/usr.sbin/nginx/src/mail/ngx_mail_proxy_module.c
index 4ea608ceafa..41cbcf6e312 100644
--- a/usr.sbin/nginx/src/mail/ngx_mail_proxy_module.c
+++ b/usr.sbin/nginx/src/mail/ngx_mail_proxy_module.c
@@ -542,17 +542,40 @@ ngx_mail_proxy_smtp_handler(ngx_event_t *rev)
CRLF) - 1
+ s->connection->addr_text.len + s->login.len + s->host.len;
+#if (NGX_HAVE_INET6)
+ if (s->connection->sockaddr->sa_family == AF_INET6) {
+ line.len += sizeof("IPV6:") - 1;
+ }
+#endif
+
line.data = ngx_pnalloc(c->pool, line.len);
if (line.data == NULL) {
ngx_mail_proxy_internal_server_error(s);
return;
}
- line.len = ngx_sprintf(line.data,
- "XCLIENT ADDR=%V%s%V NAME=%V" CRLF,
- &s->connection->addr_text,
- (s->login.len ? " LOGIN=" : ""), &s->login, &s->host)
- - line.data;
+ p = ngx_cpymem(line.data, "XCLIENT ADDR=", sizeof("XCLIENT ADDR=") - 1);
+
+#if (NGX_HAVE_INET6)
+ if (s->connection->sockaddr->sa_family == AF_INET6) {
+ p = ngx_cpymem(p, "IPV6:", sizeof("IPV6:") - 1);
+ }
+#endif
+
+ p = ngx_copy(p, s->connection->addr_text.data,
+ s->connection->addr_text.len);
+
+ if (s->login.len) {
+ p = ngx_cpymem(p, " LOGIN=", sizeof(" LOGIN=") - 1);
+ p = ngx_copy(p, s->login.data, s->login.len);
+ }
+
+ p = ngx_cpymem(p, " NAME=", sizeof(" NAME=") - 1);
+ p = ngx_copy(p, s->host.data, s->host.len);
+
+ *p++ = CR; *p++ = LF;
+
+ line.len = p - line.data;
if (s->smtp_helo.len) {
s->mail_state = ngx_smtp_xclient_helo;
@@ -657,7 +680,12 @@ ngx_mail_proxy_smtp_handler(ngx_event_t *rev)
c->log->action = NULL;
ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");
- ngx_mail_proxy_handler(s->connection->write);
+ if (s->buffer->pos == s->buffer->last) {
+ ngx_mail_proxy_handler(s->connection->write);
+
+ } else {
+ ngx_mail_proxy_handler(c->write);
+ }
return;
@@ -702,7 +730,7 @@ ngx_mail_proxy_dummy_handler(ngx_event_t *wev)
static ngx_int_t
ngx_mail_proxy_read_response(ngx_mail_session_t *s, ngx_uint_t state)
{
- u_char *p;
+ u_char *p, *m;
ssize_t n;
ngx_buf_t *b;
ngx_mail_proxy_conf_t *pcf;
@@ -779,6 +807,25 @@ ngx_mail_proxy_read_response(ngx_mail_session_t *s, ngx_uint_t state)
break;
default: /* NGX_MAIL_SMTP_PROTOCOL */
+
+ if (p[3] == '-') {
+ /* multiline reply, check if we got last line */
+
+ m = b->last - (sizeof(CRLF "200" CRLF) - 1);
+
+ while (m > p) {
+ if (m[0] == CR && m[1] == LF) {
+ break;
+ }
+
+ m--;
+ }
+
+ if (m <= p || m[5] == '-') {
+ return NGX_AGAIN;
+ }
+ }
+
switch (state) {
case ngx_smtp_start:
diff --git a/usr.sbin/nginx/src/mail/ngx_mail_smtp_handler.c b/usr.sbin/nginx/src/mail/ngx_mail_smtp_handler.c
index 21714239fcc..52fe475234a 100644
--- a/usr.sbin/nginx/src/mail/ngx_mail_smtp_handler.c
+++ b/usr.sbin/nginx/src/mail/ngx_mail_smtp_handler.c
@@ -55,7 +55,6 @@ static ngx_str_t smtp_tempunavail = ngx_string("[TEMPUNAVAIL]");
void
ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c)
{
- struct sockaddr_in *sin;
ngx_resolver_ctx_t *ctx;
ngx_mail_core_srv_conf_t *cscf;
@@ -67,11 +66,13 @@ ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c)
return;
}
- if (c->sockaddr->sa_family != AF_INET) {
+#if (NGX_HAVE_UNIX_DOMAIN)
+ if (c->sockaddr->sa_family == AF_UNIX) {
s->host = smtp_tempunavail;
ngx_mail_smtp_greeting(s, c);
return;
}
+#endif
c->log->action = "in resolving client address";
@@ -81,11 +82,8 @@ ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c)
return;
}
- /* AF_INET only */
-
- sin = (struct sockaddr_in *) c->sockaddr;
-
- ctx->addr = sin->sin_addr.s_addr;
+ ctx->addr.sockaddr = c->sockaddr;
+ ctx->addr.socklen = c->socklen;
ctx->handler = ngx_mail_smtp_resolve_addr_handler;
ctx->data = s;
ctx->timeout = cscf->resolver_timeout;
@@ -167,7 +165,6 @@ ngx_mail_smtp_resolve_name(ngx_event_t *rev)
}
ctx->name = s->host;
- ctx->type = NGX_RESOLVE_A;
ctx->handler = ngx_mail_smtp_resolve_name_handler;
ctx->data = s;
ctx->timeout = cscf->resolver_timeout;
@@ -181,10 +178,8 @@ ngx_mail_smtp_resolve_name(ngx_event_t *rev)
static void
ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx)
{
- in_addr_t addr;
ngx_uint_t i;
ngx_connection_t *c;
- struct sockaddr_in *sin;
ngx_mail_session_t *s;
s = ctx->data;
@@ -205,22 +200,29 @@ ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx)
} else {
- /* AF_INET only */
+#if (NGX_DEBUG)
+ {
+ u_char text[NGX_SOCKADDR_STRLEN];
+ ngx_str_t addr;
- sin = (struct sockaddr_in *) c->sockaddr;
+ addr.data = text;
for (i = 0; i < ctx->naddrs; i++) {
+ addr.len = ngx_sock_ntop(ctx->addrs[i].sockaddr,
+ ctx->addrs[i].socklen,
+ text, NGX_SOCKADDR_STRLEN, 0);
- addr = ctx->addrs[i];
-
- ngx_log_debug4(NGX_LOG_DEBUG_MAIL, c->log, 0,
- "name was resolved to %ud.%ud.%ud.%ud",
- (ntohl(addr) >> 24) & 0xff,
- (ntohl(addr) >> 16) & 0xff,
- (ntohl(addr) >> 8) & 0xff,
- ntohl(addr) & 0xff);
+ ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
+ "name was resolved to %V", &addr);
+ }
+ }
+#endif
- if (addr == sin->sin_addr.s_addr) {
+ for (i = 0; i < ctx->naddrs; i++) {
+ if (ngx_cmp_sockaddr(ctx->addrs[i].sockaddr, ctx->addrs[i].socklen,
+ c->sockaddr, c->socklen, 0)
+ == NGX_OK)
+ {
goto found;
}
}
@@ -321,6 +323,7 @@ ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev)
}
ngx_str_set(&s->out, smtp_invalid_pipelining);
+ s->quit = 1;
}
ngx_mail_send(c->write);
@@ -485,6 +488,10 @@ ngx_mail_smtp_auth_state(ngx_event_t *rev)
}
}
+ if (s->buffer->pos < s->buffer->last) {
+ s->blocked = 1;
+ }
+
switch (rc) {
case NGX_DONE:
@@ -504,11 +511,14 @@ ngx_mail_smtp_auth_state(ngx_event_t *rev)
case NGX_OK:
s->args.nelts = 0;
- s->buffer->pos = s->buffer->start;
- s->buffer->last = s->buffer->start;
+
+ if (s->buffer->pos == s->buffer->last) {
+ s->buffer->pos = s->buffer->start;
+ s->buffer->last = s->buffer->start;
+ }
if (s->state) {
- s->arg_start = s->buffer->start;
+ s->arg_start = s->buffer->pos;
}
ngx_mail_send(c->write);
@@ -651,9 +661,7 @@ ngx_mail_smtp_auth(ngx_mail_session_t *s, ngx_connection_t *c)
static ngx_int_t
ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c)
{
- u_char ch;
- ngx_str_t l;
- ngx_uint_t i;
+ ngx_str_t *arg, cmd;
ngx_mail_smtp_srv_conf_t *sscf;
sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
@@ -671,37 +679,20 @@ ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c)
return NGX_OK;
}
- l.len = s->buffer->last - s->buffer->start;
- l.data = s->buffer->start;
-
- for (i = 0; i < l.len; i++) {
- ch = l.data[i];
-
- if (ch != CR && ch != LF) {
- continue;
- }
-
- l.data[i] = ' ';
- }
-
- while (i) {
- if (l.data[i - 1] != ' ') {
- break;
- }
-
- i--;
- }
+ arg = s->args.elts;
+ arg += s->args.nelts - 1;
- l.len = i;
+ cmd.len = arg->data + arg->len - s->cmd.data;
+ cmd.data = s->cmd.data;
- s->smtp_from.len = l.len;
+ s->smtp_from.len = cmd.len;
- s->smtp_from.data = ngx_pnalloc(c->pool, l.len);
+ s->smtp_from.data = ngx_pnalloc(c->pool, cmd.len);
if (s->smtp_from.data == NULL) {
return NGX_ERROR;
}
- ngx_memcpy(s->smtp_from.data, l.data, l.len);
+ ngx_memcpy(s->smtp_from.data, cmd.data, cmd.len);
ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
"smtp mail from:\"%V\"", &s->smtp_from);
@@ -715,46 +706,27 @@ ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c)
static ngx_int_t
ngx_mail_smtp_rcpt(ngx_mail_session_t *s, ngx_connection_t *c)
{
- u_char ch;
- ngx_str_t l;
- ngx_uint_t i;
+ ngx_str_t *arg, cmd;
if (s->smtp_from.len == 0) {
ngx_str_set(&s->out, smtp_bad_sequence);
return NGX_OK;
}
- l.len = s->buffer->last - s->buffer->start;
- l.data = s->buffer->start;
-
- for (i = 0; i < l.len; i++) {
- ch = l.data[i];
-
- if (ch != CR && ch != LF) {
- continue;
- }
-
- l.data[i] = ' ';
- }
-
- while (i) {
- if (l.data[i - 1] != ' ') {
- break;
- }
-
- i--;
- }
+ arg = s->args.elts;
+ arg += s->args.nelts - 1;
- l.len = i;
+ cmd.len = arg->data + arg->len - s->cmd.data;
+ cmd.data = s->cmd.data;
- s->smtp_to.len = l.len;
+ s->smtp_to.len = cmd.len;
- s->smtp_to.data = ngx_pnalloc(c->pool, l.len);
+ s->smtp_to.data = ngx_pnalloc(c->pool, cmd.len);
if (s->smtp_to.data == NULL) {
return NGX_ERROR;
}
- ngx_memcpy(s->smtp_to.data, l.data, l.len);
+ ngx_memcpy(s->smtp_to.data, cmd.data, cmd.len);
ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
"smtp rcpt to:\"%V\"", &s->smtp_to);
diff --git a/usr.sbin/nginx/src/mail/ngx_mail_ssl_module.c b/usr.sbin/nginx/src/mail/ngx_mail_ssl_module.c
index 60e7a9a883a..fe88f48e43b 100644
--- a/usr.sbin/nginx/src/mail/ngx_mail_ssl_module.c
+++ b/usr.sbin/nginx/src/mail/ngx_mail_ssl_module.c
@@ -25,7 +25,7 @@ static char *ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
-static ngx_conf_enum_t ngx_http_starttls_state[] = {
+static ngx_conf_enum_t ngx_mail_starttls_state[] = {
{ ngx_string("off"), NGX_MAIL_STARTTLS_OFF },
{ ngx_string("on"), NGX_MAIL_STARTTLS_ON },
{ ngx_string("only"), NGX_MAIL_STARTTLS_ONLY },
@@ -58,7 +58,7 @@ static ngx_command_t ngx_mail_ssl_commands[] = {
ngx_mail_ssl_starttls,
NGX_MAIL_SRV_CONF_OFFSET,
offsetof(ngx_mail_ssl_conf_t, starttls),
- ngx_http_starttls_state },
+ ngx_mail_starttls_state },
{ ngx_string("ssl_certificate"),
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
@@ -116,6 +116,20 @@ static ngx_command_t ngx_mail_ssl_commands[] = {
0,
NULL },
+ { ngx_string("ssl_session_tickets"),
+ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_MAIL_SRV_CONF_OFFSET,
+ offsetof(ngx_mail_ssl_conf_t, session_tickets),
+ NULL },
+
+ { ngx_string("ssl_session_ticket_key"),
+ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_array_slot,
+ NGX_MAIL_SRV_CONF_OFFSET,
+ offsetof(ngx_mail_ssl_conf_t, session_ticket_keys),
+ NULL },
+
{ ngx_string("ssl_session_timeout"),
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_sec_slot,
@@ -184,6 +198,8 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf)
scf->prefer_server_ciphers = NGX_CONF_UNSET;
scf->builtin_session_cache = NGX_CONF_UNSET;
scf->session_timeout = NGX_CONF_UNSET;
+ scf->session_tickets = NGX_CONF_UNSET;
+ scf->session_ticket_keys = NGX_CONF_UNSET_PTR;
return scf;
}
@@ -292,15 +308,14 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
return NGX_CONF_ERROR;
}
- if (conf->ciphers.len) {
- if (SSL_CTX_set_cipher_list(conf->ssl.ctx,
- (const char *) conf->ciphers.data)
- == 0)
- {
- ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
- "SSL_CTX_set_cipher_list(\"%V\") failed",
- &conf->ciphers);
- }
+ if (SSL_CTX_set_cipher_list(conf->ssl.ctx,
+ (const char *) conf->ciphers.data)
+ == 0)
+ {
+ ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
+ "SSL_CTX_set_cipher_list(\"%V\") failed",
+ &conf->ciphers);
+ return NGX_CONF_ERROR;
}
if (conf->prefer_server_ciphers) {
@@ -313,6 +328,10 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
return NGX_CONF_ERROR;
}
+ if (ngx_ssl_ecdh_curve(cf, &conf->ssl, &conf->ecdh_curve) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
ngx_conf_merge_value(conf->builtin_session_cache,
prev->builtin_session_cache, NGX_SSL_NONE_SCACHE);
@@ -328,6 +347,24 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
return NGX_CONF_ERROR;
}
+ ngx_conf_merge_value(conf->session_tickets,
+ prev->session_tickets, 1);
+
+#ifdef SSL_OP_NO_TICKET
+ if (!conf->session_tickets) {
+ SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_NO_TICKET);
+ }
+#endif
+
+ ngx_conf_merge_ptr_value(conf->session_ticket_keys,
+ prev->session_ticket_keys, NULL);
+
+ if (ngx_ssl_session_ticket_keys(cf, &conf->ssl, conf->session_ticket_keys)
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
+
return NGX_CONF_OK;
}
diff --git a/usr.sbin/nginx/src/mail/ngx_mail_ssl_module.h b/usr.sbin/nginx/src/mail/ngx_mail_ssl_module.h
index 7f59b38ae39..bef0e515a02 100644
--- a/usr.sbin/nginx/src/mail/ngx_mail_ssl_module.h
+++ b/usr.sbin/nginx/src/mail/ngx_mail_ssl_module.h
@@ -41,6 +41,9 @@ typedef struct {
ngx_shm_zone_t *shm_zone;
+ ngx_flag_t session_tickets;
+ ngx_array_t *session_ticket_keys;
+
u_char *file;
ngx_uint_t line;
} ngx_mail_ssl_conf_t;
diff --git a/usr.sbin/nginx/src/os/unix/ngx_channel.c b/usr.sbin/nginx/src/os/unix/ngx_channel.c
index 29c69da4065..8e9069660f4 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_channel.c
+++ b/usr.sbin/nginx/src/os/unix/ngx_channel.c
@@ -34,6 +34,8 @@ ngx_write_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size,
msg.msg_control = (caddr_t) &cmsg;
msg.msg_controllen = sizeof(cmsg);
+ ngx_memzero(&cmsg, sizeof(cmsg));
+
cmsg.cm.cmsg_len = CMSG_LEN(sizeof(int));
cmsg.cm.cmsg_level = SOL_SOCKET;
cmsg.cm.cmsg_type = SCM_RIGHTS;
@@ -142,7 +144,7 @@ ngx_read_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size, ngx_log_t *log)
if ((size_t) n < sizeof(ngx_channel_t)) {
ngx_log_error(NGX_LOG_ALERT, log, 0,
- "recvmsg() returned not enough data: %uz", n);
+ "recvmsg() returned not enough data: %z", n);
return NGX_ERROR;
}
diff --git a/usr.sbin/nginx/src/os/unix/ngx_darwin_config.h b/usr.sbin/nginx/src/os/unix/ngx_darwin_config.h
index 149778c29ad..7ac86c73e82 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_darwin_config.h
+++ b/usr.sbin/nginx/src/os/unix/ngx_darwin_config.h
@@ -20,6 +20,7 @@
#include <stddef.h> /* offsetof() */
#include <stdio.h>
#include <stdlib.h>
+#include <ctype.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
diff --git a/usr.sbin/nginx/src/os/unix/ngx_darwin_init.c b/usr.sbin/nginx/src/os/unix/ngx_darwin_init.c
index e3cc5fe3eec..1bc7520cade 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_darwin_init.c
+++ b/usr.sbin/nginx/src/os/unix/ngx_darwin_init.c
@@ -59,7 +59,7 @@ sysctl_t sysctls[] = {
void
-ngx_debug_init()
+ngx_debug_init(void)
{
#if (NGX_DEBUG_MALLOC)
diff --git a/usr.sbin/nginx/src/os/unix/ngx_darwin_sendfile_chain.c b/usr.sbin/nginx/src/os/unix/ngx_darwin_sendfile_chain.c
index 078d10b2429..76c4a3a4dad 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_darwin_sendfile_chain.c
+++ b/usr.sbin/nginx/src/os/unix/ngx_darwin_sendfile_chain.c
@@ -317,9 +317,9 @@ ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
c->sent += sent;
- for (cl = in; cl; cl = cl->next) {
+ for ( /* void */ ; in; in = in->next) {
- if (ngx_buf_special(cl->buf)) {
+ if (ngx_buf_special(in->buf)) {
continue;
}
@@ -327,28 +327,28 @@ ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
break;
}
- size = ngx_buf_size(cl->buf);
+ size = ngx_buf_size(in->buf);
if (sent >= size) {
sent -= size;
- if (ngx_buf_in_memory(cl->buf)) {
- cl->buf->pos = cl->buf->last;
+ if (ngx_buf_in_memory(in->buf)) {
+ in->buf->pos = in->buf->last;
}
- if (cl->buf->in_file) {
- cl->buf->file_pos = cl->buf->file_last;
+ if (in->buf->in_file) {
+ in->buf->file_pos = in->buf->file_last;
}
continue;
}
- if (ngx_buf_in_memory(cl->buf)) {
- cl->buf->pos += (size_t) sent;
+ if (ngx_buf_in_memory(in->buf)) {
+ in->buf->pos += (size_t) sent;
}
- if (cl->buf->in_file) {
- cl->buf->file_pos += sent;
+ if (in->buf->in_file) {
+ in->buf->file_pos += sent;
}
break;
@@ -360,13 +360,11 @@ ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
if (!complete) {
wev->ready = 0;
- return cl;
+ return in;
}
- if (send >= limit || cl == NULL) {
- return cl;
+ if (send >= limit || in == NULL) {
+ return in;
}
-
- in = cl;
}
}
diff --git a/usr.sbin/nginx/src/os/unix/ngx_errno.h b/usr.sbin/nginx/src/os/unix/ngx_errno.h
index 1497c5f2f35..16cafda3107 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_errno.h
+++ b/usr.sbin/nginx/src/os/unix/ngx_errno.h
@@ -34,6 +34,8 @@ typedef int ngx_err_t;
#define NGX_ENOSPC ENOSPC
#define NGX_EPIPE EPIPE
#define NGX_EINPROGRESS EINPROGRESS
+#define NGX_ENOPROTOOPT ENOPROTOOPT
+#define NGX_EOPNOTSUPP EOPNOTSUPP
#define NGX_EADDRINUSE EADDRINUSE
#define NGX_ECONNABORTED ECONNABORTED
#define NGX_ECONNRESET ECONNRESET
@@ -50,6 +52,7 @@ typedef int ngx_err_t;
#define NGX_EILSEQ EILSEQ
#define NGX_ENOMOREFILES 0
#define NGX_ELOOP ELOOP
+#define NGX_EBADF EBADF
#if (NGX_HAVE_OPENAT)
#define NGX_EMLINK EMLINK
diff --git a/usr.sbin/nginx/src/os/unix/ngx_files.h b/usr.sbin/nginx/src/os/unix/ngx_files.h
index 9c97e2bb789..a78ec961365 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_files.h
+++ b/usr.sbin/nginx/src/os/unix/ngx_files.h
@@ -53,7 +53,9 @@ typedef struct {
#ifdef __CYGWIN__
+#ifndef NGX_HAVE_CASELESS_FILESYSTEM
#define NGX_HAVE_CASELESS_FILESYSTEM 1
+#endif
#define ngx_open_file(name, mode, create, access) \
open((const char *) name, mode|create|O_BINARY, access)
@@ -72,8 +74,8 @@ typedef struct {
#define NGX_FILE_RDWR O_RDWR
#define NGX_FILE_CREATE_OR_OPEN O_CREAT
#define NGX_FILE_OPEN 0
-#define NGX_FILE_TRUNCATE O_CREAT|O_TRUNC
-#define NGX_FILE_APPEND O_WRONLY|O_APPEND
+#define NGX_FILE_TRUNCATE (O_CREAT|O_TRUNC)
+#define NGX_FILE_APPEND (O_WRONLY|O_APPEND)
#define NGX_FILE_NONBLOCK O_NONBLOCK
#if (NGX_HAVE_OPENAT)
@@ -86,13 +88,16 @@ typedef struct {
#endif
#if defined(O_SEARCH)
-#define NGX_FILE_SEARCH O_SEARCH|NGX_FILE_DIRECTORY
+#define NGX_FILE_SEARCH (O_SEARCH|NGX_FILE_DIRECTORY)
#elif defined(O_EXEC)
-#define NGX_FILE_SEARCH O_EXEC|NGX_FILE_DIRECTORY
+#define NGX_FILE_SEARCH (O_EXEC|NGX_FILE_DIRECTORY)
+
+#elif (NGX_HAVE_O_PATH)
+#define NGX_FILE_SEARCH (O_PATH|O_RDONLY|NGX_FILE_DIRECTORY)
#else
-#define NGX_FILE_SEARCH O_RDONLY|NGX_FILE_DIRECTORY
+#define NGX_FILE_SEARCH (O_RDONLY|NGX_FILE_DIRECTORY)
#endif
#endif /* NGX_HAVE_OPENAT */
@@ -189,17 +194,6 @@ ngx_int_t ngx_create_file_mapping(ngx_file_mapping_t *fm);
void ngx_close_file_mapping(ngx_file_mapping_t *fm);
-#if (NGX_HAVE_CASELESS_FILESYSTEM)
-
-#define ngx_filename_cmp(s1, s2, n) strncasecmp((char *) s1, (char *) s2, n)
-
-#else
-
-#define ngx_filename_cmp ngx_memcmp
-
-#endif
-
-
#define ngx_realpath(p, r) (u_char *) realpath((char *) p, (char *) r)
#define ngx_realpath_n "realpath()"
#define ngx_getcwd(buf, size) (getcwd((char *) buf, size) != NULL)
diff --git a/usr.sbin/nginx/src/os/unix/ngx_freebsd_config.h b/usr.sbin/nginx/src/os/unix/ngx_freebsd_config.h
index 5b3ff278c01..92b2928c8b5 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_freebsd_config.h
+++ b/usr.sbin/nginx/src/os/unix/ngx_freebsd_config.h
@@ -16,6 +16,7 @@
#include <stddef.h> /* offsetof() */
#include <stdio.h>
#include <stdlib.h>
+#include <ctype.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
@@ -94,6 +95,11 @@ typedef struct aiocb ngx_aiocb_t;
#define NGX_LISTEN_BACKLOG -1
+#ifdef __DragonFly__
+#define NGX_KEEPALIVE_FACTOR 1000
+#endif
+
+
#if (__FreeBSD_version < 430000 || __FreeBSD_version < 500012)
pid_t rfork_thread(int flags, void *stack, int (*func)(void *arg), void *arg);
diff --git a/usr.sbin/nginx/src/os/unix/ngx_freebsd_init.c b/usr.sbin/nginx/src/os/unix/ngx_freebsd_init.c
index aeeceaf2565..c4c12dd741c 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_freebsd_init.c
+++ b/usr.sbin/nginx/src/os/unix/ngx_freebsd_init.c
@@ -72,7 +72,7 @@ sysctl_t sysctls[] = {
void
-ngx_debug_init()
+ngx_debug_init(void)
{
#if (NGX_DEBUG_MALLOC)
diff --git a/usr.sbin/nginx/src/os/unix/ngx_freebsd_rfork_thread.c b/usr.sbin/nginx/src/os/unix/ngx_freebsd_rfork_thread.c
index 530ec4a53bb..e92f9a9fdd7 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_freebsd_rfork_thread.c
+++ b/usr.sbin/nginx/src/os/unix/ngx_freebsd_rfork_thread.c
@@ -271,7 +271,7 @@ ngx_init_threads(int n, size_t size, ngx_cycle_t *cycle)
ngx_tid_t
-ngx_thread_self()
+ngx_thread_self(void)
{
ngx_int_t tid;
diff --git a/usr.sbin/nginx/src/os/unix/ngx_freebsd_rfork_thread.h b/usr.sbin/nginx/src/os/unix/ngx_freebsd_rfork_thread.h
index 2c238f79ca6..ff160449dad 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_freebsd_rfork_thread.h
+++ b/usr.sbin/nginx/src/os/unix/ngx_freebsd_rfork_thread.h
@@ -57,7 +57,7 @@ extern size_t ngx_thread_stack_size;
static ngx_inline ngx_int_t
-ngx_gettid()
+ngx_gettid(void)
{
char *sp;
@@ -83,7 +83,7 @@ ngx_gettid()
}
-ngx_tid_t ngx_thread_self();
+ngx_tid_t ngx_thread_self(void);
typedef ngx_uint_t ngx_tls_key_t;
diff --git a/usr.sbin/nginx/src/os/unix/ngx_freebsd_sendfile_chain.c b/usr.sbin/nginx/src/os/unix/ngx_freebsd_sendfile_chain.c
index f58b5c20fe1..11cec82269a 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_freebsd_sendfile_chain.c
+++ b/usr.sbin/nginx/src/os/unix/ngx_freebsd_sendfile_chain.c
@@ -231,7 +231,7 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
&& c->tcp_nopush == NGX_TCP_NOPUSH_UNSET)
{
if (ngx_tcp_nopush(c->fd) == NGX_ERROR) {
- err = ngx_errno;
+ err = ngx_socket_errno;
/*
* there is a tiny chance to be interrupted, however,
@@ -368,9 +368,9 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
c->sent += sent;
- for (cl = in; cl; cl = cl->next) {
+ for ( /* void */ ; in; in = in->next) {
- if (ngx_buf_special(cl->buf)) {
+ if (ngx_buf_special(in->buf)) {
continue;
}
@@ -378,28 +378,28 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
break;
}
- size = ngx_buf_size(cl->buf);
+ size = ngx_buf_size(in->buf);
if (sent >= size) {
sent -= size;
- if (ngx_buf_in_memory(cl->buf)) {
- cl->buf->pos = cl->buf->last;
+ if (ngx_buf_in_memory(in->buf)) {
+ in->buf->pos = in->buf->last;
}
- if (cl->buf->in_file) {
- cl->buf->file_pos = cl->buf->file_last;
+ if (in->buf->in_file) {
+ in->buf->file_pos = in->buf->file_last;
}
continue;
}
- if (ngx_buf_in_memory(cl->buf)) {
- cl->buf->pos += (size_t) sent;
+ if (ngx_buf_in_memory(in->buf)) {
+ in->buf->pos += (size_t) sent;
}
- if (cl->buf->in_file) {
- cl->buf->file_pos += sent;
+ if (in->buf->in_file) {
+ in->buf->file_pos += sent;
}
break;
@@ -407,7 +407,7 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
#if (NGX_HAVE_AIO_SENDFILE)
if (c->busy_sendfile) {
- return cl;
+ return in;
}
#endif
@@ -421,7 +421,7 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
*/
wev->ready = 0;
- return cl;
+ return in;
}
if (eintr) {
@@ -430,13 +430,11 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
if (!complete) {
wev->ready = 0;
- return cl;
+ return in;
}
- if (send >= limit || cl == NULL) {
- return cl;
+ if (send >= limit || in == NULL) {
+ return in;
}
-
- in = cl;
}
}
diff --git a/usr.sbin/nginx/src/os/unix/ngx_linux_config.h b/usr.sbin/nginx/src/os/unix/ngx_linux_config.h
index 2834032dea0..72594bac0ea 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_linux_config.h
+++ b/usr.sbin/nginx/src/os/unix/ngx_linux_config.h
@@ -22,6 +22,7 @@
#include <stddef.h> /* offsetof() */
#include <stdio.h>
#include <stdlib.h>
+#include <ctype.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
@@ -51,7 +52,6 @@
#include <malloc.h> /* memalign() */
#include <limits.h> /* IOV_MAX */
#include <sys/ioctl.h>
-#include <sys/sysctl.h>
#include <crypt.h>
#include <sys/utsname.h> /* uname() */
@@ -77,8 +77,14 @@ extern ssize_t sendfile(int s, int fd, int32_t *offset, size_t size);
#endif
-#if (NGX_HAVE_POLL || NGX_HAVE_RTSIG)
+#if (NGX_HAVE_POLL)
+#include <poll.h>
+#endif
+
+
+#if (NGX_HAVE_RTSIG)
#include <poll.h>
+#include <sys/sysctl.h>
#endif
diff --git a/usr.sbin/nginx/src/os/unix/ngx_linux_sendfile_chain.c b/usr.sbin/nginx/src/os/unix/ngx_linux_sendfile_chain.c
index e8f3d5a894e..16395f94337 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_linux_sendfile_chain.c
+++ b/usr.sbin/nginx/src/os/unix/ngx_linux_sendfile_chain.c
@@ -24,7 +24,7 @@
* so we limit it to 2G-1 bytes.
*/
-#define NGX_SENDFILE_LIMIT 2147483647L
+#define NGX_SENDFILE_MAXSIZE 2147483647L
#if (IOV_MAX > 64)
@@ -63,8 +63,8 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
/* the maximum limit size is 2G-1 - the page size */
- if (limit == 0 || limit > (off_t) (NGX_SENDFILE_LIMIT - ngx_pagesize)) {
- limit = NGX_SENDFILE_LIMIT - ngx_pagesize;
+ if (limit == 0 || limit > (off_t) (NGX_SENDFILE_MAXSIZE - ngx_pagesize)) {
+ limit = NGX_SENDFILE_MAXSIZE - ngx_pagesize;
}
@@ -163,7 +163,7 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
(const void *) &tcp_nodelay, sizeof(int)) == -1)
{
- err = ngx_errno;
+ err = ngx_socket_errno;
/*
* there is a tiny chance to be interrupted, however,
@@ -181,7 +181,7 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
} else {
c->tcp_nodelay = NGX_TCP_NODELAY_UNSET;
- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
"no tcp_nodelay");
}
}
@@ -189,7 +189,7 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
if (c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) {
if (ngx_tcp_nopush(c->fd) == NGX_ERROR) {
- err = ngx_errno;
+ err = ngx_socket_errno;
/*
* there is a tiny chance to be interrupted, however,
@@ -325,9 +325,9 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
c->sent += sent;
- for (cl = in; cl; cl = cl->next) {
+ for ( /* void */ ; in; in = in->next) {
- if (ngx_buf_special(cl->buf)) {
+ if (ngx_buf_special(in->buf)) {
continue;
}
@@ -335,28 +335,28 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
break;
}
- size = ngx_buf_size(cl->buf);
+ size = ngx_buf_size(in->buf);
if (sent >= size) {
sent -= size;
- if (ngx_buf_in_memory(cl->buf)) {
- cl->buf->pos = cl->buf->last;
+ if (ngx_buf_in_memory(in->buf)) {
+ in->buf->pos = in->buf->last;
}
- if (cl->buf->in_file) {
- cl->buf->file_pos = cl->buf->file_last;
+ if (in->buf->in_file) {
+ in->buf->file_pos = in->buf->file_last;
}
continue;
}
- if (ngx_buf_in_memory(cl->buf)) {
- cl->buf->pos += (size_t) sent;
+ if (ngx_buf_in_memory(in->buf)) {
+ in->buf->pos += (size_t) sent;
}
- if (cl->buf->in_file) {
- cl->buf->file_pos += sent;
+ if (in->buf->in_file) {
+ in->buf->file_pos += sent;
}
break;
@@ -368,13 +368,11 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
if (!complete) {
wev->ready = 0;
- return cl;
+ return in;
}
- if (send >= limit || cl == NULL) {
- return cl;
+ if (send >= limit || in == NULL) {
+ return in;
}
-
- in = cl;
}
}
diff --git a/usr.sbin/nginx/src/os/unix/ngx_posix_config.h b/usr.sbin/nginx/src/os/unix/ngx_posix_config.h
index 4cf90cc9897..d725659dfac 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_posix_config.h
+++ b/usr.sbin/nginx/src/os/unix/ngx_posix_config.h
@@ -39,6 +39,7 @@
#include <stddef.h> /* offsetof() */
#include <stdio.h>
#include <stdlib.h>
+#include <ctype.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
diff --git a/usr.sbin/nginx/src/os/unix/ngx_process.c b/usr.sbin/nginx/src/os/unix/ngx_process.c
index 4ef3582e8a2..6f3f38556ab 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_process.c
+++ b/usr.sbin/nginx/src/os/unix/ngx_process.c
@@ -291,9 +291,14 @@ ngx_init_signals(ngx_log_t *log)
sa.sa_handler = sig->handler;
sigemptyset(&sa.sa_mask);
if (sigaction(sig->signo, &sa, NULL) == -1) {
+#if (NGX_VALGRIND)
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ "sigaction(%s) failed, ignored", sig->signame);
+#else
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
"sigaction(%s) failed", sig->signame);
return NGX_ERROR;
+#endif
}
}
diff --git a/usr.sbin/nginx/src/os/unix/ngx_process_cycle.c b/usr.sbin/nginx/src/os/unix/ngx_process_cycle.c
index 77fdcf21fe5..078b1251e90 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_process_cycle.c
+++ b/usr.sbin/nginx/src/os/unix/ngx_process_cycle.c
@@ -356,6 +356,8 @@ ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type)
ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start worker processes");
+ ngx_memzero(&ch, sizeof(ngx_channel_t));
+
ch.command = NGX_CMD_OPEN_CHANNEL;
for (i = 0; i < n; i++) {
@@ -402,6 +404,8 @@ ngx_start_cache_manager_processes(ngx_cycle_t *cycle, ngx_uint_t respawn)
&ngx_cache_manager_ctx, "cache manager process",
respawn ? NGX_PROCESS_JUST_RESPAWN : NGX_PROCESS_RESPAWN);
+ ngx_memzero(&ch, sizeof(ngx_channel_t));
+
ch.command = NGX_CMD_OPEN_CHANNEL;
ch.pid = ngx_processes[ngx_process_slot].pid;
ch.slot = ngx_process_slot;
@@ -461,6 +465,8 @@ ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo)
ngx_err_t err;
ngx_channel_t ch;
+ ngx_memzero(&ch, sizeof(ngx_channel_t));
+
#if (NGX_BROKEN_SCM_RIGHTS)
ch.command = 0;
@@ -531,7 +537,7 @@ ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo)
}
ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
- "kill (%P, %d)" , ngx_processes[i].pid, signo);
+ "kill (%P, %d)", ngx_processes[i].pid, signo);
if (kill(ngx_processes[i].pid, signo) == -1) {
err = ngx_errno;
@@ -562,6 +568,8 @@ ngx_reap_children(ngx_cycle_t *cycle)
ngx_channel_t ch;
ngx_core_conf_t *ccf;
+ ngx_memzero(&ch, sizeof(ngx_channel_t));
+
ch.command = NGX_CMD_CLOSE_CHANNEL;
ch.fd = -1;
@@ -703,10 +711,13 @@ ngx_master_process_exit(ngx_cycle_t *cycle)
* ngx_cycle->pool is already destroyed.
*/
- ngx_exit_log_file.fd = ngx_cycle->log->file->fd;
- ngx_exit_log = *ngx_cycle->log;
+ ngx_exit_log = *ngx_log_get_file_log(ngx_cycle->log);
+
+ ngx_exit_log_file.fd = ngx_exit_log.file->fd;
ngx_exit_log.file = &ngx_exit_log_file;
+ ngx_exit_log.next = NULL;
+ ngx_exit_log.writer = NULL;
ngx_exit_cycle.log = &ngx_exit_log;
ngx_exit_cycle.files = ngx_cycle->files;
@@ -1000,6 +1011,8 @@ nochroot:
"sigprocmask() failed");
}
+ srandom((ngx_pid << 16) ^ ngx_time());
+
/*
* disable deleting previous events for the listening sockets because
* in the worker processes there are no events at all at this point
@@ -1085,8 +1098,8 @@ ngx_worker_process_exit(ngx_cycle_t *cycle)
&& !c[i].read->resolver)
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
- "open socket #%d left in connection %ui",
- c[i].fd, i);
+ "*%uA open socket #%d left in connection %ui",
+ c[i].number, c[i].fd, i);
ngx_debug_quit = 1;
}
}
@@ -1104,10 +1117,12 @@ ngx_worker_process_exit(ngx_cycle_t *cycle)
* ngx_cycle->pool is already destroyed.
*/
- ngx_exit_log_file.fd = ngx_cycle->log->file->fd;
+ ngx_exit_log = *ngx_log_get_file_log(ngx_cycle->log);
- ngx_exit_log = *ngx_cycle->log;
+ ngx_exit_log_file.fd = ngx_exit_log.file->fd;
ngx_exit_log.file = &ngx_exit_log_file;
+ ngx_exit_log.next = NULL;
+ ngx_exit_log.writer = NULL;
ngx_exit_cycle.log = &ngx_exit_log;
ngx_exit_cycle.files = ngx_cycle->files;
diff --git a/usr.sbin/nginx/src/os/unix/ngx_readv_chain.c b/usr.sbin/nginx/src/os/unix/ngx_readv_chain.c
index 7b6badfa825..8836c817dad 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_readv_chain.c
+++ b/usr.sbin/nginx/src/os/unix/ngx_readv_chain.c
@@ -129,6 +129,7 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain)
"%d available bytes", rev->available);
#endif
+ rev->ready = 0;
rev->eof = 1;
rev->available = 0;
}
@@ -136,7 +137,7 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain)
return n;
}
- if (n < size) {
+ if (n < size && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) {
rev->ready = 0;
}
diff --git a/usr.sbin/nginx/src/os/unix/ngx_recv.c b/usr.sbin/nginx/src/os/unix/ngx_recv.c
index 6a4a0996624..86675dfdd8f 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_recv.c
+++ b/usr.sbin/nginx/src/os/unix/ngx_recv.c
@@ -80,6 +80,7 @@ ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size)
* even if kqueue reported about available data
*/
+ rev->ready = 0;
rev->eof = 1;
rev->available = 0;
}
@@ -87,7 +88,9 @@ ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size)
return n;
}
- if ((size_t) n < size) {
+ if ((size_t) n < size
+ && !(ngx_event_flags & NGX_USE_GREEDY_EVENT))
+ {
rev->ready = 0;
}
diff --git a/usr.sbin/nginx/src/os/unix/ngx_solaris_config.h b/usr.sbin/nginx/src/os/unix/ngx_solaris_config.h
index e664ba826c0..ddfd984577e 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_solaris_config.h
+++ b/usr.sbin/nginx/src/os/unix/ngx_solaris_config.h
@@ -22,6 +22,7 @@
#include <stddef.h> /* offsetof() */
#include <stdio.h>
#include <stdlib.h>
+#include <ctype.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
diff --git a/usr.sbin/nginx/src/os/unix/ngx_solaris_sendfilev_chain.c b/usr.sbin/nginx/src/os/unix/ngx_solaris_sendfilev_chain.c
index 520eaaab4c7..37bb09d961a 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_solaris_sendfilev_chain.c
+++ b/usr.sbin/nginx/src/os/unix/ngx_solaris_sendfilev_chain.c
@@ -207,9 +207,9 @@ ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
c->sent += sent;
- for (cl = in; cl; cl = cl->next) {
+ for ( /* void */ ; in; in = in->next) {
- if (ngx_buf_special(cl->buf)) {
+ if (ngx_buf_special(in->buf)) {
continue;
}
@@ -217,28 +217,28 @@ ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
break;
}
- size = ngx_buf_size(cl->buf);
+ size = ngx_buf_size(in->buf);
if ((off_t) sent >= size) {
sent = (size_t) ((off_t) sent - size);
- if (ngx_buf_in_memory(cl->buf)) {
- cl->buf->pos = cl->buf->last;
+ if (ngx_buf_in_memory(in->buf)) {
+ in->buf->pos = in->buf->last;
}
- if (cl->buf->in_file) {
- cl->buf->file_pos = cl->buf->file_last;
+ if (in->buf->in_file) {
+ in->buf->file_pos = in->buf->file_last;
}
continue;
}
- if (ngx_buf_in_memory(cl->buf)) {
- cl->buf->pos += sent;
+ if (ngx_buf_in_memory(in->buf)) {
+ in->buf->pos += sent;
}
- if (cl->buf->in_file) {
- cl->buf->file_pos += sent;
+ if (in->buf->in_file) {
+ in->buf->file_pos += sent;
}
break;
@@ -250,13 +250,11 @@ ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
if (!complete) {
wev->ready = 0;
- return cl;
+ return in;
}
- if (send >= limit || cl == NULL) {
- return cl;
+ if (send >= limit || in == NULL) {
+ return in;
}
-
- in = cl;
}
}