summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorRobert Nagy <robert@cvs.openbsd.org>2012-05-13 09:14:59 +0000
committerRobert Nagy <robert@cvs.openbsd.org>2012-05-13 09:14:59 +0000
commitf939b758f1c469a3c6f7305fc788c5ffc29dbffe (patch)
treee3fd61d4112b4577e4afd9036b7de700fad9fb54 /usr.sbin
parent530053e003eb12ce7182895fcceef65346227fa5 (diff)
update to nginx-1.2.0
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/nginx/CHANGES401
-rw-r--r--usr.sbin/nginx/CHANGES.ru403
-rw-r--r--usr.sbin/nginx/auto/lib/pcre/conf29
-rw-r--r--usr.sbin/nginx/auto/lib/pcre/make2
-rw-r--r--usr.sbin/nginx/auto/modules17
-rw-r--r--usr.sbin/nginx/auto/options20
-rw-r--r--usr.sbin/nginx/auto/os/freebsd8
-rw-r--r--usr.sbin/nginx/auto/os/linux9
-rw-r--r--usr.sbin/nginx/auto/os/solaris3
-rw-r--r--usr.sbin/nginx/auto/sources13
-rw-r--r--usr.sbin/nginx/auto/summary2
-rw-r--r--usr.sbin/nginx/auto/types/sizeof3
-rw-r--r--usr.sbin/nginx/auto/types/typedef2
-rw-r--r--usr.sbin/nginx/auto/types/uintptr_t11
-rwxr-xr-xusr.sbin/nginx/auto/unix103
-rw-r--r--usr.sbin/nginx/conf/fastcgi.conf1
-rw-r--r--usr.sbin/nginx/conf/fastcgi_params1
-rw-r--r--usr.sbin/nginx/conf/scgi_params1
-rw-r--r--usr.sbin/nginx/conf/uwsgi_params1
-rw-r--r--usr.sbin/nginx/man/nginx.88
-rw-r--r--usr.sbin/nginx/src/core/nginx.c22
-rw-r--r--usr.sbin/nginx/src/core/nginx.h4
-rw-r--r--usr.sbin/nginx/src/core/ngx_buf.c16
-rw-r--r--usr.sbin/nginx/src/core/ngx_buf.h4
-rw-r--r--usr.sbin/nginx/src/core/ngx_conf_file.c15
-rw-r--r--usr.sbin/nginx/src/core/ngx_conf_file.h2
-rw-r--r--usr.sbin/nginx/src/core/ngx_connection.c53
-rw-r--r--usr.sbin/nginx/src/core/ngx_connection.h6
-rw-r--r--usr.sbin/nginx/src/core/ngx_core.h5
-rw-r--r--usr.sbin/nginx/src/core/ngx_cycle.c2
-rw-r--r--usr.sbin/nginx/src/core/ngx_cycle.h4
-rw-r--r--usr.sbin/nginx/src/core/ngx_file.c2
-rw-r--r--usr.sbin/nginx/src/core/ngx_inet.c19
-rw-r--r--usr.sbin/nginx/src/core/ngx_murmurhash.h2
-rw-r--r--usr.sbin/nginx/src/core/ngx_open_file_cache.c381
-rw-r--r--usr.sbin/nginx/src/core/ngx_open_file_cache.h10
-rw-r--r--usr.sbin/nginx/src/core/ngx_output_chain.c3
-rw-r--r--usr.sbin/nginx/src/core/ngx_parse.h3
-rw-r--r--usr.sbin/nginx/src/core/ngx_rbtree.c3
-rw-r--r--usr.sbin/nginx/src/core/ngx_regex.c268
-rw-r--r--usr.sbin/nginx/src/core/ngx_regex.h8
-rw-r--r--usr.sbin/nginx/src/core/ngx_resolver.c109
-rw-r--r--usr.sbin/nginx/src/core/ngx_resolver.h15
-rw-r--r--usr.sbin/nginx/src/core/ngx_shmtx.c113
-rw-r--r--usr.sbin/nginx/src/core/ngx_shmtx.h13
-rw-r--r--usr.sbin/nginx/src/core/ngx_slab.c6
-rw-r--r--usr.sbin/nginx/src/core/ngx_slab.h2
-rw-r--r--usr.sbin/nginx/src/core/ngx_string.c43
-rw-r--r--usr.sbin/nginx/src/core/ngx_times.c4
-rw-r--r--usr.sbin/nginx/src/event/modules/ngx_epoll_module.c4
-rw-r--r--usr.sbin/nginx/src/event/modules/ngx_eventport_module.c2
-rw-r--r--usr.sbin/nginx/src/event/modules/ngx_kqueue_module.c2
-rw-r--r--usr.sbin/nginx/src/event/ngx_event.c42
-rw-r--r--usr.sbin/nginx/src/event/ngx_event_openssl.c4
-rw-r--r--usr.sbin/nginx/src/event/ngx_event_pipe.c193
-rw-r--r--usr.sbin/nginx/src/event/ngx_event_pipe.h3
-rw-r--r--usr.sbin/nginx/src/event/ngx_event_timer.c5
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_access_module.c13
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_browser_module.c8
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_chunked_filter_module.c2
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_degradation_module.c2
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_fastcgi_module.c166
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_flv_module.c8
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_geo_module.c6
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_gzip_filter_module.c26
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_gzip_static_module.c8
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_headers_filter_module.c50
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_image_filter_module.c4
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_index_module.c24
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_limit_conn_module.c747
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_limit_req_module.c422
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_limit_zone_module.c553
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_log_module.c40
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_memcached_module.c22
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_mp4_module.c8
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_proxy_module.c1461
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_realip_module.c14
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_scgi_module.c111
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_split_clients_module.c19
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_ssi_filter_module.c22
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_static_module.c8
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_upstream_ip_hash_module.c4
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_upstream_keepalive_module.c570
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_userid_filter_module.c6
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_uwsgi_module.c103
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_xslt_filter_module.c208
-rw-r--r--usr.sbin/nginx/src/http/modules/perl/nginx.pm3
-rw-r--r--usr.sbin/nginx/src/http/modules/perl/nginx.xs4
-rw-r--r--usr.sbin/nginx/src/http/ngx_http.c9
-rw-r--r--usr.sbin/nginx/src/http/ngx_http.h1
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_busy_lock.c4
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_cache.h13
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_copy_filter_module.c7
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_core_module.c340
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_core_module.h15
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_file_cache.c278
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_parse.c72
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_postpone_filter_module.c8
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_request.c88
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_request.h6
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_request_body.c2
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_script.c6
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_upstream.c247
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_upstream.h21
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_upstream_round_robin.c28
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_upstream_round_robin.h1
-rw-r--r--usr.sbin/nginx/src/http/ngx_http_variables.c127
-rw-r--r--usr.sbin/nginx/src/mail/ngx_mail.c13
-rw-r--r--usr.sbin/nginx/src/mail/ngx_mail.h12
-rw-r--r--usr.sbin/nginx/src/mail/ngx_mail_core_module.c115
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_daemon.c3
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_darwin.h3
-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.c30
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_darwin_sendfile_chain.c16
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_errno.h5
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_files.h51
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_freebsd.h3
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_freebsd_config.h2
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_freebsd_init.c7
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_freebsd_rfork_thread.c4
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_freebsd_sendfile_chain.c18
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_gcc_atomic_sparc64.h2
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_linux_config.h1
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_linux_sendfile_chain.c10
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_os.h1
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_posix_config.h3
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_process.c61
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_process.h1
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_process_cycle.c21
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_readv_chain.c8
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_setaffinity.c69
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_setaffinity.h23
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_setproctitle.c2
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_solaris_config.h2
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_solaris_sendfilev_chain.c14
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_writev_chain.c10
-rw-r--r--usr.sbin/nginx/src/pcre/pcre_study.c1527
138 files changed, 8565 insertions, 1818 deletions
diff --git a/usr.sbin/nginx/CHANGES b/usr.sbin/nginx/CHANGES
index e5ceff6d112..75026b6bc5d 100644
--- a/usr.sbin/nginx/CHANGES
+++ b/usr.sbin/nginx/CHANGES
@@ -1,22 +1,80 @@
-Changes with nginx 1.0.15 12 Apr 2012
+Changes with nginx 1.2.0 23 Apr 2012
+
+ *) Bugfix: a segmentation fault might occur in a worker process if the
+ "try_files" directive was used; the bug had appeared in 1.1.19.
+
+ *) Bugfix: response might be truncated if there were more than IOV_MAX
+ buffers used.
+
+ *) Bugfix: in the "crop" parameter of the "image_filter" directive.
+ Thanks to Maxim Bublis.
+
+
+Changes with nginx 1.1.19 12 Apr 2012
*) Security: specially crafted mp4 file might allow to overwrite memory
locations in a worker process if the ngx_http_mp4_module was used,
potentially resulting in arbitrary code execution (CVE-2012-2089).
Thanks to Matthew Daley.
+ *) Bugfix: nginx/Windows might be terminated abnormally.
+ Thanks to Vincent Lee.
+
+ *) Bugfix: nginx hogged CPU if all servers in an upstream were marked as
+ "backup".
+
+ *) Bugfix: the "allow" and "deny" directives might be inherited
+ incorrectly if they were used with IPv6 addresses.
+
+ *) Bugfix: the "modern_browser" and "ancient_browser" directives might
+ be inherited incorrectly.
+
+ *) Bugfix: timeouts might be handled incorrectly on Solaris/SPARC.
+
*) Bugfix: in the ngx_http_mp4_module.
-Changes with nginx 1.0.14 15 Mar 2012
+Changes with nginx 1.1.18 28 Mar 2012
+
+ *) Change: keepalive connections are no longer disabled for Safari by
+ default.
+
+ *) Feature: the $connection_requests variable.
+
+ *) Feature: $tcpinfo_rtt, $tcpinfo_rttvar, $tcpinfo_snd_cwnd and
+ $tcpinfo_rcv_space variables.
+
+ *) Feature: the "worker_cpu_affinity" directive now works on FreeBSD.
+
+ *) Feature: the "xslt_param" and "xslt_string_param" directives.
+ Thanks to Samuel Behan.
+
+ *) Bugfix: in configure tests.
+ Thanks to Piotr Sikora.
+
+ *) Bugfix: in the ngx_http_xslt_filter_module.
+
+ *) Bugfix: nginx could not be built on Debian GNU/Hurd.
+
+
+Changes with nginx 1.1.17 15 Mar 2012
*) Security: content of previously freed memory might be sent to a
client if backend returned specially crafted response.
Thanks to Matthew Daley.
+ *) Bugfix: in the embedded perl module if used from SSI.
+ Thanks to Matthew Daley.
+
+ *) Bugfix: in the ngx_http_uwsgi_module.
+
+
+Changes with nginx 1.1.16 29 Feb 2012
+
+ *) Change: the simultaneous subrequest limit has been raised to 200.
-Changes with nginx 1.0.13 05 Mar 2012
+ *) Feature: the "from" parameter of the "disable_symlinks" directive.
*) Feature: the "return" and "error_page" directives can now be used to
return 307 redirections.
@@ -26,74 +84,113 @@ Changes with nginx 1.0.13 05 Mar 2012
specified at global level.
Thanks to Roman Arutyunyan.
+ *) Bugfix: a segmentation fault might occur in a worker process if the
+ "proxy_http_version 1.1" or "fastcgi_keep_conn on" directives were
+ used.
+
*) Bugfix: memory leaks.
Thanks to Lanshun Zhou.
+ *) Bugfix: in the "disable_symlinks" directive.
+
+ *) Bugfix: on ZFS filesystem disk cache size might be calculated
+ incorrectly; the bug had appeared in 1.0.1.
+
+ *) Bugfix: nginx could not be built by the icc 12.1 compiler.
+
+ *) Bugfix: nginx could not be built by gcc on Solaris; the bug had
+ appeared in 1.1.15.
+
+
+Changes with nginx 1.1.15 15 Feb 2012
+
+ *) Feature: the "disable_symlinks" directive.
+
+ *) Feature: the "proxy_cookie_domain" and "proxy_cookie_path"
+ directives.
+
*) Bugfix: nginx might log incorrect error "upstream prematurely closed
connection" instead of correct "upstream sent too big header" one.
Thanks to Feibo Li.
- *) Bugfix: on ZFS filesystem disk cache size might be calculated
- incorrectly; the bug had appeared in 1.0.1.
+ *) Bugfix: nginx could not be built with the ngx_http_perl_module if the
+ --with-openssl option was used.
*) Bugfix: the number of internal redirects to named locations was not
limited.
+ *) Bugfix: calling $r->flush() multiple times might cause errors in the
+ ngx_http_gzip_filter_module.
+
*) Bugfix: temporary files might be not removed if the "proxy_store"
directive was used with SSI includes.
*) Bugfix: in some cases non-cacheable variables (such as the $args
variable) returned old empty cached value.
+ *) Bugfix: a segmentation fault might occur in a worker process if too
+ many SSI subrequests were issued simultaneously; the bug had appeared
+ in 0.7.25.
+
+
+Changes with nginx 1.1.14 30 Jan 2012
+
+ *) Feature: multiple "limit_req" limits may be used simultaneously.
+
+ *) Bugfix: in error handling while connecting to a backend.
+ Thanks to Piotr Sikora.
+
+ *) Bugfix: in AIO error handling on FreeBSD.
+
+ *) Bugfix: in the OpenSSL library initialization.
+
*) Bugfix: the "proxy_redirect" directives might be inherited
incorrectly.
- *) Bugfix: nginx could not be built with the ngx_http_perl_module if the
- --with-openssl option was used.
-
- *) Bugfix: nginx could not be built by the icc 12.1 compiler.
+ *) Bugfix: memory leak during reconfiguration if the "pcre_jit"
+ directive was used.
-Changes with nginx 1.0.12 06 Feb 2012
+Changes with nginx 1.1.13 16 Jan 2012
*) Feature: the "TLSv1.1" and "TLSv1.2" parameters of the
"ssl_protocols" directive.
- *) Feature: the "if" SSI command supports captures in regular
- expressions.
-
- *) Bugfix: the "if" SSI command did not work inside the "block" command.
+ *) Bugfix: the "limit_req" directive parameters were not inherited
+ correctly; the bug had appeared in 1.1.12.
- *) Bugfix: in AIO error handling on FreeBSD.
+ *) Bugfix: the "proxy_redirect" directive incorrectly processed
+ "Refresh" header if regular expression were used.
- *) Bugfix: in the OpenSSL library initialization.
+ *) Bugfix: the "proxy_cache_use_stale" directive with "error" parameter
+ did not return answer from cache if there were no live upstreams.
*) Bugfix: the "worker_cpu_affinity" directive might not work.
- *) Bugfix: the "limit_conn_log_level" and "limit_req_log_level"
- directives might not work.
+ *) Bugfix: nginx could not be built on Solaris; the bug had appeared in
+ 1.1.12.
- *) Bugfix: the "read_ahead" directive might not work combined with
- "try_files" and "open_file_cache".
+ *) Bugfix: in the ngx_http_mp4_module.
- *) Bugfix: the "proxy_cache_use_stale" directive with "error" parameter
- did not return answer from cache if there were no live upstreams.
- *) Bugfix: a segmentation fault might occur in a worker process if small
- time was used in the "inactive" parameter of the "proxy_cache_path"
- directive.
+Changes with nginx 1.1.12 26 Dec 2011
- *) Bugfix: responses from cache might hang.
+ *) Change: a "proxy_pass" directive without URI part now uses changed
+ URI after redirection with the "error_page" directive.
+ Thanks to Lanshun Zhou.
- *) Bugfix: in error handling while connecting to a backend.
- Thanks to Piotr Sikora.
+ *) Feature: the "proxy/fastcgi/scgi/uwsgi_cache_lock",
+ "proxy/fastcgi/scgi/uwsgi_cache_lock_timeout" directives.
- *) Bugfix: in the "epoll" event method.
- Thanks to Yichun Zhang.
+ *) Feature: the "pcre_jit" directive.
- *) Bugfix: the $sent_http_cache_control variable might contain a wrong
- value if the "expires" directive was used.
- Thanks to Yichun Zhang.
+ *) Feature: the "if" SSI command supports captures in regular
+ expressions.
+
+ *) Bugfix: the "if" SSI command did not work inside the "block" command.
+
+ *) Bugfix: the "limit_conn_log_level" and "limit_req_log_level"
+ directives might not work.
*) Bugfix: the "limit_rate" directive did not allow to use full
throughput, even if limit value was very high.
@@ -101,52 +198,114 @@ Changes with nginx 1.0.12 06 Feb 2012
*) Bugfix: the "sendfile_max_chunk" directive did not work, if the
"limit_rate" directive was used.
- *) Bugfix: nginx could not be built on Solaris; the bug had appeared in
- 1.0.11.
+ *) Bugfix: a "proxy_pass" directive without URI part always used
+ original request URI if variables were used.
+
+ *) Bugfix: a "proxy_pass" directive without URI part might use original
+ request after redirection with the "try_files" directive.
+ Thanks to Lanshun Zhou.
*) Bugfix: in the ngx_http_scgi_module.
*) Bugfix: in the ngx_http_mp4_module.
+ *) Bugfix: nginx could not be built on Solaris; the bug had appeared in
+ 1.1.9.
+
+
+Changes with nginx 1.1.11 12 Dec 2011
+
+ *) Feature: the "so_keepalive" parameter of the "listen" directive.
+ Thanks to Vsevolod Stakhov.
+
+ *) Feature: the "if_not_empty" parameter of the
+ "fastcgi/scgi/uwsgi_param" directives.
+
+ *) Feature: the $https variable.
+
+ *) Feature: the "proxy_redirect" directive supports variables in the
+ first parameter.
+
+ *) Feature: the "proxy_redirect" directive supports regular expressions.
+
+ *) Bugfix: the $sent_http_cache_control variable might contain a wrong
+ value if the "expires" directive was used.
+ Thanks to Yichun Zhang.
+
+ *) Bugfix: the "read_ahead" directive might not work combined with
+ "try_files" and "open_file_cache".
+
+ *) Bugfix: a segmentation fault might occur in a worker process if small
+ time was used in the "inactive" parameter of the "proxy_cache_path"
+ directive.
+
+ *) Bugfix: responses from cache might hang.
+
+
+Changes with nginx 1.1.10 30 Nov 2011
-Changes with nginx 1.0.11 15 Dec 2011
+ *) Bugfix: a segmentation fault occured in a worker process if AIO was
+ used on Linux; the bug had appeared in 1.1.9.
+
+
+Changes with nginx 1.1.9 28 Nov 2011
*) Change: now double quotes are encoded in an "echo" SSI-command
output.
Thanks to Zaur Abasmirzoev.
- *) Feature: the "image_filter_sharpen" directive.
+ *) Feature: the "valid" parameter of the "resolver" directive. By
+ default TTL returned by a DNS server is used.
+ Thanks to Kirill A. Korinskiy.
+
+ *) Bugfix: nginx might hang after a worker process abnormal termination.
*) Bugfix: a segmentation fault might occur in a worker process if SNI
- was used; the bug had appeared in 1.0.9.
+ was used; the bug had appeared in 1.1.2.
+
+ *) Bugfix: in the "keepalive_disable" directive; the bug had appeared in
+ 1.1.8.
+ Thanks to Alexander Usov.
*) Bugfix: SIGWINCH signal did not work after first binary upgrade; the
- bug had appeared in 1.0.9.
+ bug had appeared in 1.1.1.
- *) Bugfix: the "If-Modified-Since", "If-Range", etc. client request
- header lines might be passed to backend while caching; or not passed
- without caching if caching was enabled in another part of the
- configuration.
+ *) Bugfix: backend responses with length not matching "Content-Length"
+ header line are no longer cached.
*) Bugfix: in the "scgi_param" directive, if complex parameters were
used.
- *) Bugfix: "add_header" and "expires" directives did not work if a
- request was proxied and response status code was 206.
-
- *) Bugfix: in the "expires @time" directive.
+ *) Bugfix: in the "epoll" event method.
+ Thanks to Yichun Zhang.
*) Bugfix: in the ngx_http_flv_module.
Thanks to Piotr Sikora.
*) Bugfix: in the ngx_http_mp4_module.
+ *) Bugfix: IPv6 addresses are now handled properly in a request line and
+ in a "Host" request header line.
+
+ *) Bugfix: "add_header" and "expires" directives did not work if a
+ request was proxied and response status code was 206.
+
*) Bugfix: nginx could not be built on FreeBSD 10.
*) Bugfix: nginx could not be built on AIX.
-Changes with nginx 1.0.10 15 Nov 2011
+Changes with nginx 1.1.8 14 Nov 2011
+
+ *) Change: the ngx_http_limit_zone_module was renamed to the
+ ngx_http_limit_conn_module.
+
+ *) Change: the "limit_zone" directive was superseded by the
+ "limit_conn_zone" directive with a new syntax.
+
+ *) Feature: support for multiple "limit_conn" limits on the same level.
+
+ *) Feature: the "image_filter_sharpen" directive.
*) Bugfix: a segmentation fault might occur in a worker process if
resolver got a big DNS response.
@@ -155,34 +314,54 @@ Changes with nginx 1.0.10 15 Nov 2011
*) Bugfix: in cache key calculation if internal MD5 implementation was
used; the bug had appeared in 1.0.4.
+ *) Bugfix: the "If-Modified-Since", "If-Range", etc. client request
+ header lines might be passed to backend while caching; or not passed
+ without caching if caching was enabled in another part of the
+ configuration.
+
*) Bugfix: the module ngx_http_mp4_module sent incorrect
"Content-Length" response header line if the "start" argument was
used.
Thanks to Piotr Sikora.
-Changes with nginx 1.0.9 01 Nov 2011
+Changes with nginx 1.1.7 31 Oct 2011
+
+ *) Feature: support of several DNS servers in the "resolver" directive.
+ Thanks to Kirill A. Korinskiy.
+
+ *) Bugfix: a segmentation fault occurred on start or during
+ reconfiguration if the "ssl" directive was used at http level and
+ there was no "ssl_certificate" defined.
+
+ *) Bugfix: reduced memory consumption while proxying big files if they
+ were buffered to disk.
+
+ *) Bugfix: a segmentation fault might occur in a worker process if
+ "proxy_http_version 1.1" directive was used.
+
+ *) Bugfix: in the "expires @time" directive.
+
+
+Changes with nginx 1.1.6 17 Oct 2011
+
+ *) Change in internal API: now module context data are cleared while
+ internal redirect to named location.
+ Requested by Yichun Zhang.
+
+ *) Change: if a server in an upstream failed, only one request will be
+ sent to it after fail_timeout; the server will be considered alive if
+ it will successfully respond to the request.
*) Change: now the 0x7F-0x1F characters are escaped as \xXX in an
access_log.
- *) Change: now SIGWINCH signal works only in daemon mode.
-
*) Feature: "proxy/fastcgi/scgi/uwsgi_ignore_headers" directives support
the following additional values: X-Accel-Limit-Rate,
X-Accel-Buffering, X-Accel-Charset.
*) Feature: decrease of memory consumption if SSL is used.
- *) Feature: accept filters are now supported on NetBSD.
-
- *) Feature: the "uwsgi_buffering" and "scgi_buffering" directives.
- Thanks to Peter Smit.
-
- *) Bugfix: a segmentation fault occurred on start or while
- reconfiguration if the "ssl" directive was used at http level and
- there was no "ssl_certificate" defined.
-
*) Bugfix: some UTF-8 characters were processed incorrectly.
Thanks to Alexey Kuts.
@@ -199,10 +378,18 @@ Changes with nginx 1.0.9 01 Nov 2011
*) Bugfix: the module ngx_http_mp4_module did not support seeking on
32-bit platforms.
+
+Changes with nginx 1.1.5 05 Oct 2011
+
+ *) Feature: the "uwsgi_buffering" and "scgi_buffering" directives.
+ Thanks to Peter Smit.
+
*) Bugfix: non-cacheable responses might be cached if
"proxy_cache_bypass" directive was used.
Thanks to John Ferlito.
+ *) Bugfix: in HTTP/1.1 support in the ngx_http_proxy_module.
+
*) Bugfix: cached responses with an empty body were returned
incorrectly; the bug had appeared in 0.8.31.
@@ -211,26 +398,17 @@ Changes with nginx 1.0.9 01 Nov 2011
*) Bugfix: in the "return" directive.
- *) Bugfix: the "ssl_verify_client", "ssl_verify_depth", and
- "ssl_prefer_server_ciphers" directives might work incorrectly if SNI
- was used.
+ *) Bugfix: the "ssl_session_cache builtin" directive caused segmentation
+ fault; the bug had appeared in 1.1.1.
-Changes with nginx 1.0.8 01 Oct 2011
+Changes with nginx 1.1.4 20 Sep 2011
- *) Bugfix: nginx could not be built --with-http_mp4_module and without
- --with-debug option.
-
-
-Changes with nginx 1.0.7 30 Sep 2011
-
- *) Change: now if total size of all ranges is greater than source
- response size, then nginx disables ranges and returns just the source
- response.
+ *) Feature: the ngx_http_upstream_keepalive module.
- *) Feature: the "max_ranges" directive.
+ *) Feature: the "proxy_http_version" directive.
- *) Feature: the module ngx_http_mp4_module.
+ *) Feature: the "fastcgi_keep_conn" directive.
*) Feature: the "worker_aio_requests" directive.
@@ -240,17 +418,57 @@ Changes with nginx 1.0.7 30 Sep 2011
*) Bugfix: in Linux AIO error processing.
Thanks to Hagai Avrahami.
+ *) Bugfix: reduced memory consumption for long-lived requests.
+
+ *) Bugfix: the module ngx_http_mp4_module did not support 64-bit MP4
+ "co64" atom.
+
+
+Changes with nginx 1.1.3 14 Sep 2011
+
+ *) Feature: the module ngx_http_mp4_module.
+
*) Bugfix: in Linux AIO combined with open_file_cache.
*) Bugfix: open_file_cache did not update file info on retest if file
was not atomically changed.
- *) Bugfix: reduced memory consumption for long-lived requests.
+ *) Bugfix: nginx could not be built on MacOSX 10.7.
+
+
+Changes with nginx 1.1.2 05 Sep 2011
+
+ *) Change: now if total size of all ranges is greater than source
+ response size, then nginx disables ranges and returns just the source
+ response.
+
+ *) Feature: the "max_ranges" directive.
+
+ *) Bugfix: the "ssl_verify_client", "ssl_verify_depth", and
+ "ssl_prefer_server_ciphers" directives might work incorrectly if SNI
+ was used.
*) Bugfix: in the "proxy/fastcgi/scgi/uwsgi_ignore_client_abort"
directives.
- *) Bugfix: nginx could not be built on MacOSX 10.7.
+
+Changes with nginx 1.1.1 22 Aug 2011
+
+ *) Change: now cache loader processes either as many files as specified
+ by "loader_files" parameter or works no longer than time specified by
+ the "loader_threshold" parameter during each iteration.
+
+ *) Change: now SIGWINCH signal works only in daemon mode.
+
+ *) Feature: now shared zones and caches use POSIX semaphores on Solaris.
+ Thanks to Den Ivanov.
+
+ *) Feature: accept filters are now supported on NetBSD.
+
+ *) Bugfix: nginx could not be built on Linux 3.0.
+
+ *) Bugfix: nginx did not use gzipping in some cases; the bug had
+ appeared in 1.1.0.
*) Bugfix: request body might be processed incorrectly if client used
pipelining.
@@ -269,11 +487,18 @@ Changes with nginx 1.0.7 30 Sep 2011
*) Bugfix: a segmentation fault might occur in a worker process if many
backup servers were used in an upstream.
+ *) Bugfix: a segmentation fault might occur in a worker process if
+ "fastcgi/scgi/uwsgi_param" directives were used with values starting
+ with "HTTP_"; the bug had appeared in 0.8.40.
+
-Changes with nginx 1.0.6 29 Aug 2011
+Changes with nginx 1.1.0 01 Aug 2011
*) Feature: cache loader run time decrease.
+ *) Feature: "loader_files", "loader_sleep", and "loader_threshold"
+ options of the "proxy/fastcgi/scgi/uwsgi_cache_path" directives.
+
*) Feature: loading time decrease of configuration with large number of
HTTPS sites.
@@ -281,31 +506,27 @@ Changes with nginx 1.0.6 29 Aug 2011
Thanks to Adrian Kotelba.
*) Feature: the "lingering_close" directive.
-
- *) Feature: now shared zones and caches use POSIX semaphores on Solaris.
- Thanks to Den Ivanov.
-
- *) Bugfix: nginx could not be built on Linux 3.0.
-
- *) Bugfix: a segmentation fault might occur in a worker process if
- "fastcgi/scgi/uwsgi_param" directives were used with values starting
- with "HTTP_"; the bug had appeared in 0.8.40.
+ Thanks to Maxim Dounin.
*) Bugfix: in closing connection for pipelined requests.
+ Thanks to Maxim Dounin.
*) Bugfix: nginx did not disable gzipping if client sent "gzip;q=0" in
"Accept-Encoding" request header line.
*) Bugfix: in timeout in unbuffered proxied mode.
+ Thanks to Maxim Dounin.
*) Bugfix: memory leaks when a "proxy_pass" directive contains variables
and proxies to an HTTPS backend.
+ Thanks to Maxim Dounin.
*) Bugfix: in parameter validaiton of a "proxy_pass" directive with
variables.
Thanks to Lanshun Zhou.
*) Bugfix: SSL did not work on QNX.
+ Thanks to Maxim Dounin.
*) Bugfix: SSL modules could not be built by gcc 4.6 without
--with-debug option.
@@ -365,8 +586,8 @@ Changes with nginx 1.0.3 25 May 2011
testing IPv4 address mapped to IPv6 address, if access or deny rules
were defined only for IPv6; the bug had appeared in 0.8.22.
- *) Bugfix: a cached response may be broken if proxy/fastcgi/scgi/
- uwsgi_cache_bypass and proxy/fastcgi/scgi/uwsgi_no_cache directive
+ *) Bugfix: a cached response may be broken if "proxy/fastcgi/scgi/
+ uwsgi_cache_bypass" and "proxy/fastcgi/scgi/uwsgi_no_cache" directive
values were different; the bug had appeared in 0.8.46.
@@ -2132,7 +2353,7 @@ Changes with nginx 0.7.15 08 Sep 2008
Changes with nginx 0.7.14 01 Sep 2008
*) Change: now the ssl_certificate and ssl_certificate_key directives
- have not default values.
+ have no default values.
*) Feature: the "listen" directive supports the "ssl" parameter.
diff --git a/usr.sbin/nginx/CHANGES.ru b/usr.sbin/nginx/CHANGES.ru
index 0bfe8f75ac8..9d62688079d 100644
--- a/usr.sbin/nginx/CHANGES.ru
+++ b/usr.sbin/nginx/CHANGES.ru
@@ -1,5 +1,17 @@
-Изменения в nginx 1.0.15 12.04.2012
+Изменения в nginx 1.2.0 23.04.2012
+
+ *) Исправление: в рабочем процессе мог произойти segmentation fault,
+ если использовалась директива try_files; ошибка появилась в 1.1.19.
+
+ *) Исправление: ответ мог быть передан не полностью, если использовалось
+ больше IOV_MAX буферов.
+
+ *) Исправление: в работе параметра crop директивы image_filter.
+ Спасибо Maxim Bublis.
+
+
+Изменения в nginx 1.1.19 12.04.2012
*) Безопасность: при обработке специально созданного mp4 файла модулем
ngx_http_mp4_module могли перезаписываться области памяти рабочего
@@ -7,17 +19,64 @@
(CVE-2012-2089).
Спасибо Matthew Daley.
+ *) Исправление: nginx/Windows мог завершаться аварийно.
+ Спасибо Vincent Lee.
+
+ *) Исправление: nginx нагружал процессор, если все серверы в upstream'е
+ были помечены флагом backup.
+
+ *) Исправление: директивы allow и deny могли наследоваться некорректно,
+ если в них использовались IPv6 адреса.
+
+ *) Исправление: директивы modern_browser и ancient_browser могли
+ наследоваться некорректно.
+
+ *) Исправление: таймауты могли работать некорректно на Solaris/SPARC.
+
*) Исправление: в модуле ngx_http_mp4_module.
-Изменения в nginx 1.0.14 15.03.2012
+Изменения в nginx 1.1.18 28.03.2012
+
+ *) Изменение: теперь keepalive соединения не запрещены для Safari по
+ умолчанию.
+
+ *) Добавление: переменная $connection_requests.
+
+ *) Добавление: переменные $tcpinfo_rtt, $tcpinfo_rttvar,
+ $tcpinfo_snd_cwnd и $tcpinfo_rcv_space.
+
+ *) Добавление: директива worker_cpu_affinity теперь работает на FreeBSD.
+
+ *) Добавление: директивы xslt_param и xslt_string_param.
+ Спасибо Samuel Behan.
+
+ *) Исправление: в configure.
+ Спасибо Piotr Sikora.
+
+ *) Исправление: в модуле ngx_http_xslt_filter_module.
+
+ *) Исправление: nginx не собирался на Debian GNU/Hurd.
+
+
+Изменения в nginx 1.1.17 15.03.2012
*) Безопасность: содержимое ранее освобождённой памяти могло быть
отправлено клиенту, если бэкенд возвращал специально созданный ответ.
Спасибо Matthew Daley.
+ *) Исправление: при использовании встроенного перла из SSI.
+ Спасибо Matthew Daley.
+
+ *) Исправление: в модуле ngx_http_uwsgi_module.
+
+
+Изменения в nginx 1.1.16 29.02.2012
-Изменения в nginx 1.0.13 05.03.2012
+ *) Изменение: ограничение на количество одновременных подзапросов
+ поднято до 200.
+
+ *) Добавление: параметр from в директиве disable_symlinks.
*) Добавление: директивы return и error_page теперь могут использоваться
для возврата перенаправлений с кодом 307.
@@ -27,74 +86,114 @@
задана директива error_log.
Спасибо Роману Арутюняну.
+ *) Исправление: в рабочем процессе мог произойти segmentation fault,
+ если использовались директивы "proxy_http_version 1.1" или
+ "fastcgi_keep_conn on".
+
*) Исправление: утечек памяти.
Спасибо Lanshun Zhou.
+ *) Исправление: в директиве disable_symlinks.
+
+ *) Исправление: при использовании ZFS размер кэша на диске мог считаться
+ некорректно; ошибка появилась в 1.0.1.
+
+ *) Исправление: nginx не собирался компилятором icc 12.1.
+
+ *) Исправление: nginx не собирался gcc на Solaris; ошибка появилась в
+ 1.1.15.
+
+
+Изменения в nginx 1.1.15 15.02.2012
+
+ *) Добавление: директива disable_symlinks.
+
+ *) Добавление: директивы proxy_cookie_domain и proxy_cookie_path.
+
*) Исправление: nginx мог некорректно сообщать об ошибке "upstream
prematurely closed connection" вместо "upstream sent too big header".
Спасибо Feibo Li.
- *) Исправление: при использовании ZFS размер кэша на диске мог считаться
- некорректно; ошибка появилась в 1.0.1.
+ *) Исправление: nginx не собирался с модулем ngx_http_perl_module, если
+ использовался параметр --with-openssl.
*) Исправление: количество внутренних перенаправлений в именованные
location'ы не ограничивалось.
+ *) Исправление: вызов $r->flush() несколько раз подряд мог приводить к
+ ошибкам в модуле ngx_http_gzip_filter_module.
+
*) Исправление: при использовании директивы proxy_store с
SSI-подзапросами временные файлы могли не удаляться.
*) Исправление: в некоторых случаях некэшируемые переменные (такие, как
$args) возвращали старое пустое закэшированное значение.
- *) Исправление: директивы proxy_redirect могли наследоваться
- некорректно.
+ *) Исправление: в рабочем процессе мог произойти segmentation fault,
+ если одновременно создавалось слишком много SSI-подзапросов; ошибка
+ появилась в 0.7.25.
- *) Исправление: nginx не собирался с модулем ngx_http_perl_module, если
- использовался параметр --with-openssl.
- *) Исправление: nginx не собирался компилятором icc 12.1.
+Изменения в nginx 1.1.14 30.01.2012
+ *) Добавление: теперь можно указать несколько ограничений limit_req
+ одновременно.
-Изменения в nginx 1.0.12 06.02.2012
+ *) Исправление: в обработке ошибок при соединении с бэкендом.
+ Спасибо Piotr Sikora.
- *) Добавление: параметры TLSv1.1 и TLSv1.2 в директиве ssl_protocols.
+ *) Исправление: в обработке ошибок при использовании AIO на FreeBSD.
- *) Добавление: SSI команда if поддерживает выделения в регулярных
- выражениях.
+ *) Исправление: в инициализации библиотеки OpenSSL.
- *) Исправление: SSI команда if не работала внутри команды block.
+ *) Исправление: директивы proxy_redirect могли наследоваться
+ некорректно.
- *) Исправление: в обработке ошибок при использовании AIO на FreeBSD.
+ *) Исправление: утечки памяти при переконфигурации, если использовалась
+ директива pcre_jit.
- *) Исправление: в инициализации библиотеки OpenSSL.
- *) Исправление: директива worker_cpu_affinity могла не работать.
+Изменения в nginx 1.1.13 16.01.2012
- *) Исправление: директивы limit_conn_log_level и limit_req_log_level
- могли не работать.
+ *) Добавление: параметры TLSv1.1 и TLSv1.2 в директиве ssl_protocols.
- *) Исправление: директива read_ahead могла не работать при использовании
- совместно с try_files и open_file_cache.
+ *) Исправление: параметры директивы limit_req наследовались некорректно;
+ ошибка появилась в 1.1.12.
+
+ *) Исправление: директива proxy_redirect некорректно обрабатывала
+ заголовок Refresh при использовании регулярных выражений.
*) Исправление: директива proxy_cache_use_stale с параметром error не
возвращала ответ из кэша, если все бэкенды были признаны
неработающими.
- *) Исправление: если в параметре inactive директивы proxy_cache_path
- было указано малое время, в рабочем процессе мог произойти
- segmentation fault.
+ *) Исправление: директива worker_cpu_affinity могла не работать.
- *) Исправление: ответы из кэша могли зависать.
+ *) Исправление: nginx не собирался на Solaris; ошибка появилась в
+ 1.1.12.
- *) Исправление: в обработке ошибок при соединении с бэкендом.
- Спасибо Piotr Sikora.
+ *) Исправление: в модуле ngx_http_mp4_module.
- *) Исправление: в методе epoll.
- Спасибо Yichun Zhang.
- *) Исправление: переменная $sent_http_cache_control могла содержать
- неверное значение при использовании директивы expires.
- Спасибо Yichun Zhang.
+Изменения в nginx 1.1.12 26.12.2011
+
+ *) Изменение: после перенаправления запроса с помощью директивы
+ error_page директива proxy_pass без URI теперь использует изменённый
+ URI.
+ Спасибо Lanshun Zhou.
+
+ *) Добавление: директивы proxy/fastcgi/scgi/uwsgi_cache_lock,
+ proxy/fastcgi/scgi/uwsgi_cache_lock_timeout.
+
+ *) Добавление: директива pcre_jit.
+
+ *) Добавление: SSI команда if поддерживает выделения в регулярных
+ выражениях.
+
+ *) Исправление: SSI команда if не работала внутри команды block.
+
+ *) Исправление: директивы limit_conn_log_level и limit_req_log_level
+ могли не работать.
*) Исправление: директива limit_rate не позволяла передавать на полной
скорости, даже если был указан очень большой лимит.
@@ -102,52 +201,116 @@
*) Исправление: директива sendfile_max_chunk не работала, если
использовалась директива limit_rate.
- *) Исправление: nginx не собирался на Solaris; ошибка появилась в
- 1.0.11.
+ *) Исправление: если в директиве proxy_pass использовались переменные и
+ не был указан URI, всегда использовался URI исходного запроса.
+
+ *) Исправление: после перенаправления запроса с помощью директивы
+ try_files директива proxy_pass без URI могла использовать URI
+ исходного запроса.
+ Спасибо Lanshun Zhou.
*) Исправление: в модуле ngx_http_scgi_module.
*) Исправление: в модуле ngx_http_mp4_module.
+ *) Исправление: nginx не собирался на Solaris; ошибка появилась в 1.1.9.
+
+
+Изменения в nginx 1.1.11 12.12.2011
+
+ *) Добавление: параметр so_keepalive в директиве listen.
+ Спасибо Всеволоду Стахову.
+
+ *) Добавление: параметр if_not_empty в директивах
+ fastcgi/scgi/uwsgi_param.
+
+ *) Добавление: переменная $https.
+
+ *) Добавление: директива proxy_redirect поддерживает переменные в первом
+ параметре.
+
+ *) Добавление: директива proxy_redirect поддерживает регулярные
+ выражения.
+
+ *) Исправление: переменная $sent_http_cache_control могла содержать
+ неверное значение при использовании директивы expires.
+ Спасибо Yichun Zhang.
+
+ *) Исправление: директива read_ahead могла не работать при использовании
+ совместно с try_files и open_file_cache.
+
+ *) Исправление: если в параметре inactive директивы proxy_cache_path
+ было указано малое время, в рабочем процессе мог произойти
+ segmentation fault.
+
+ *) Исправление: ответы из кэша могли зависать.
+
+
+Изменения в nginx 1.1.10 30.11.2011
+
+ *) Исправление: при использовании AIO на Linux в рабочем процессе
+ происходил segmentation fault; ошибка появилась в 1.1.9.
+
-Изменения в nginx 1.0.11 15.12.2011
+Изменения в nginx 1.1.9 28.11.2011
*) Изменение: теперь двойные кавычки экранируется при выводе
SSI-командой echo.
Спасибо Зауру Абасмирзоеву.
- *) Добавление: директива image_filter_sharpen.
+ *) Добавление: параметр valid в директиве resolver. По умолчанию теперь
+ используется TTL, возвращённый DNS-сервером.
+ Спасибо Кириллу Коринскому.
+
+ *) Исправление: nginx мог перестать отвечать, если рабочий процесс
+ завершался аварийно.
*) Исправление: в рабочем процессе мог произойти segmentation fault,
- если использовалось SNI; ошибка появилась в 1.0.9.
+ если использовалось SNI; ошибка появилась в 1.1.2.
+
+ *) Исправление: в директиве keepalive_disable; ошибка появилась в 1.1.8.
+ Спасибо Александру Усову.
*) Исправление: сигнал SIGWINCH переставал работать после первого
- обновления исполняемого файла; ошибка появилась в 1.0.9.
+ обновления исполняемого файла; ошибка появилась в 1.1.1.
- *) Исправление: строки "If-Modified-Since", "If-Range" и им подобные в
- заголовке запроса клиента могли передаваться бэкенду при кэшировании;
- или не передаваться при выключенном кэшировании, если кэширование
- было включено в другой части конфигурации.
+ *) Исправление: теперь ответы бэкендов, длина которых не соответствует
+ заголовку Content-Length, не кэширутся.
*) Исправление: в директиве scgi_param при использовании составных
параметров.
- *) Исправление: директивы add_header и expires не работали для ответов с
- кодом 206, если запрос проксировался.
-
- *) Исправление: в директиве "expires @time".
+ *) Исправление: в методе epoll.
+ Спасибо Yichun Zhang.
*) Исправление: в модуле ngx_http_flv_module.
Спасибо Piotr Sikora.
*) Исправление: в модуле ngx_http_mp4_module.
+ *) Исправление: теперь nginx понимает IPv6-адреса в строке запроса и в
+ заголовке Host.
+
+ *) Исправление: директивы add_header и expires не работали для ответов с
+ кодом 206, если запрос проксировался.
+
*) Исправление: nginx не собирался на FreeBSD 10.
*) Исправление: nginx не собирался на AIX.
-Изменения в nginx 1.0.10 15.11.2011
+Изменения в nginx 1.1.8 14.11.2011
+
+ *) Изменение: модуль ngx_http_limit_zone_module переименован в
+ ngx_http_limit_conn_module.
+
+ *) Изменение: директива limit_zone заменена директивой limit_conn_zone с
+ новым синтаксисом.
+
+ *) Добавление: поддержка ограничения по нескольким limit_conn на одном
+ уровне.
+
+ *) Добавление: директива image_filter_sharpen.
*) Исправление: в рабочем процессе мог произойти segmentation fault,
если resolver получил большой DNS-ответ.
@@ -156,33 +319,54 @@
*) Исправление: в вычислении ключа для кэширования, если использовалась
внутренняя реализация MD5; ошибка появилась в 1.0.4.
+ *) Исправление: строки "If-Modified-Since", "If-Range" и им подобные в
+ заголовке запроса клиента могли передаваться бэкенду при кэшировании;
+ или не передаваться при выключенном кэшировании, если кэширование
+ было включено в другой части конфигурации.
+
*) Исправление: модуль ngx_http_mp4_module выдавал неверную строку
"Content-Length" в заголовке ответа, использовался аргумент start.
Спасибо Piotr Sikora.
-Изменения в nginx 1.0.9 01.11.2011
+Изменения в nginx 1.1.7 31.10.2011
+
+ *) Добавление: поддержка нескольких DNS серверов в директиве "resolver".
+ Спасибо Кириллу Коринскому.
+
+ *) Исправление: на старте или во время переконфигурации происходил
+ segmentation fault, если директива ssl использовалась на уровне http
+ и не был указан ssl_certificate.
+
+ *) Исправление: уменьшено потребление памяти при проксировании больших
+ файлов, если они буферизировались на диск.
+
+ *) Исправление: в рабочем процессе мог произойти segmentation fault,
+ если использовалась директива "proxy_http_version 1.1".
+
+ *) Исправление: в директиве "expires @time".
+
+
+Изменения в nginx 1.1.6 17.10.2011
+
+ *) Изменение во внутреннем API: теперь при внутреннем редиректе в
+ именованный location контексты модулей очищаются.
+ По запросу Yichun Zhang.
+
+ *) Изменение: теперь если сервер, описанный в блоке upstream, был
+ признан неработающим, то после истечения fail_timeout на него будет
+ отправлен только один запрос; сервер будет считаться работающим, если
+ успешно ответит на этот запрос.
*) Изменение: теперь символы 0x7F-0xFF в access_log записываются в виде
\xXX.
- *) Изменение: SIGWINCH сигнал теперь работает только в режиме демона.
-
*) Добавление: директивы "proxy/fastcgi/scgi/uwsgi_ignore_headers"
теперь поддерживают значения X-Accel-Limit-Rate, X-Accel-Buffering и
X-Accel-Charset.
*) Добавление: уменьшение потребления памяти при использовании SSL.
- *) Добавление: теперь на NetBSD поддерживаются accept фильтры.
-
- *) Добавление: директивы uwsgi_buffering и scgi_buffering.
- Спасибо Peter Smit.
-
- *) Исправление: на старте или во время переконфигурации происходил
- segmentation fault, если директива ssl использовалась на уровне http
- и не был указан ssl_certificate.
-
*) Исправление: некоторые UTF-8 символы обрабатывались неправильно.
Спасибо Алексею Куцу.
@@ -201,10 +385,19 @@
*) Исправление: модуль ngx_http_mp4_module не поддерживал перемотку на
32-битных платформах.
+
+Изменения в nginx 1.1.5 05.10.2011
+
+ *) Добавление: директивы uwsgi_buffering и scgi_buffering.
+ Спасибо Peter Smit.
+
*) Исправление: при использовании proxy_cache_bypass могли быть
закэшированы некэшируемые ответы.
Спасибо John Ferlito.
+ *) Исправление: в модуле ngx_http_proxy_module при работе с бэкендами по
+ HTTP/1.1.
+
*) Исправление: закэшированные ответы с пустым телом возвращались
некорректно; ошибка появилась в 0.8.31.
@@ -213,26 +406,17 @@
*) Исправление: в директиве return.
- *) Исправление: директивы ssl_verify_client, ssl_verify_depth и
- ssl_prefer_server_cipher могли работать некорректно, если
- использовался SNI.
-
-
-Изменения в nginx 1.0.8 01.10.2011
+ *) Исправление: при использовании директивы "ssl_session_cache builtin"
+ происходил segmentation fault; ошибка появилась в 1.1.1.
- *) Исправление: nginx не собирался с модулем ngx_http_mp4_module и без
- параметра --with-debug.
+Изменения в nginx 1.1.4 20.09.2011
-Изменения в nginx 1.0.7 30.09.2011
-
- *) Изменение: теперь, если суммарный размер всех диапазонов больше
- размера исходного ответа, то nginx возвращает только исходный ответ,
- не обрабатывая диапазоны.
+ *) Добавление: модуль ngx_http_upstream_keepalive.
- *) Добавление: директива max_ranges.
+ *) Добавление: директива proxy_http_version.
- *) Добавление: модуль ngx_http_mp4_module.
+ *) Добавление: директива fastcgi_keep_conn.
*) Добавление: директива worker_aio_requests.
@@ -242,17 +426,58 @@
*) Исправление: в обработке ошибок при работе с Linux AIO.
Спасибо Hagai Avrahami.
+ *) Исправление: уменьшено потребление памяти для долгоживущих запросов.
+
+ *) Исправление: модуль ngx_http_mp4_module не поддерживал 64-битный
+ MP4-атом co64.
+
+
+Изменения в nginx 1.1.3 14.09.2011
+
+ *) Добавление: модуль ngx_http_mp4_module.
+
*) Исправление: в Linux AIO, используемым совместно с open_file_cache.
*) Исправление: open_file_cache не обновлял информацию о файле, если
файл был изменён не атомарно.
- *) Исправление: уменьшено потребление памяти для долгоживущих запросов.
+ *) Исправление: nginx не собирался на MacOSX 10.7.
+
+
+Изменения в nginx 1.1.2 05.09.2011
+
+ *) Изменение: теперь, если суммарный размер всех диапазонов больше
+ размера исходного ответа, то nginx возвращает только исходный ответ,
+ не обрабатывая диапазоны.
+
+ *) Добавление: директива max_ranges.
+
+ *) Исправление: директивы ssl_verify_client, ssl_verify_depth и
+ ssl_prefer_server_cipher могли работать некорректно, если
+ использовался SNI.
*) Исправление: в директивах proxy/fastcgi/scgi/
uwsgi_ignore_client_abort.
- *) Исправление: nginx не собирался на MacOSX 10.7.
+
+Изменения в nginx 1.1.1 22.08.2011
+
+ *) Изменение: теперь загрузчик кэша за каждую итерацию либо обрабатывает
+ число файлов, указанное в параметре load_files, либо работает не
+ дольше времени, указанного в параметре loader_threshold.
+
+ *) Изменение: SIGWINCH сигнал теперь работает только в режиме демона.
+
+ *) Добавление: теперь разделяемые зоны и кэши используют семафоры POSIX
+ на Solaris.
+ Спасибо Денису Иванову.
+
+ *) Добавление: теперь на NetBSD поддерживаются accept фильтры.
+
+ *) Исправление: nginx не собирался на Linux 3.0.
+
+ *) Исправление: в некоторых случаях nginx не использовал сжатие; ошибка
+ появилась в 1.1.0.
*) Исправление: обработка тела запроса могла быть неверной, если клиент
использовал pipelining.
@@ -272,11 +497,18 @@
*) Исправление: при использовании большого количества backup-серверов в
рабочем процессе мог произойти segmentation fault.
+ *) Исправление: при использовании директив fastcgi/scgi/uwsgi_param со
+ значениями, начинающимися со строки "HTTP_", в рабочем процессе мог
+ произойти segmentation fault; ошибка появилась в 0.8.40.
+
-Изменения в nginx 1.0.6 29.08.2011
+Изменения в nginx 1.1.0 01.08.2011
*) Добавление: уменьшение времени работы загрузчика кэша.
+ *) Добавление: параметры loader_files, loader_sleep и loader_threshold
+ директив proxy/fastcgi/scgi/uwsgi_cache_path.
+
*) Добавление: уменьшение времени загрузки конфигураций с большим
количеством HTTPS серверов.
@@ -284,32 +516,27 @@
Спасибо Adrian Kotelba.
*) Добавление: директива lingering_close.
-
- *) Добавление: теперь разделяемые зоны и кэши используют семафоры POSIX
- на Solaris.
- Спасибо Денису Иванову.
-
- *) Исправление: nginx не собирался на Linux 3.0.
-
- *) Исправление: при использовании директив fastcgi/scgi/uwsgi_param со
- значениями, начинающимися со строки "HTTP_", в рабочем процессе мог
- произойти segmentation fault; ошибка появилась в 0.8.40.
+ Спасибо Максиму Дунину.
*) Исправление: закрытия соединения для pipelined-запросов.
+ Спасибо Максиму Дунину.
*) Исправление: nginx не запрещал сжатие при получении значения
"gzip;q=0" в строке "Accept-Encoding" в заголовке запроса клиента.
*) Исправление: таймаута при небуферизированном проксировании.
+ Спасибо Максиму Дунину.
*) Исправление: утечки памяти при использовании переменных в директиве
proxy_pass при работе с бэкендом по HTTPS.
+ Спасибо Максиму Дунину.
*) Исправление: в проверке параметра директивы proxy_pass, заданного
переменными.
Спасибо Lanshun Zhou.
*) Исправление: SSL не работал на QNX.
+ Спасибо Максиму Дунину.
*) Исправление: SSL модули не собирались gcc 4.6 без параметра
--with-debug.
diff --git a/usr.sbin/nginx/auto/lib/pcre/conf b/usr.sbin/nginx/auto/lib/pcre/conf
index d183079e93d..69dae0425e6 100644
--- a/usr.sbin/nginx/auto/lib/pcre/conf
+++ b/usr.sbin/nginx/auto/lib/pcre/conf
@@ -5,8 +5,6 @@
if [ $PCRE != NONE ]; then
CORE_INCS="$CORE_INCS $PCRE"
- CORE_DEPS="$CORE_DEPS $REGEX_DEPS"
- CORE_SRCS="$CORE_SRCS $REGEX_SRCS"
case "$NGX_CC_NAME" in
@@ -82,6 +80,12 @@ if [ $PCRE != NONE ]; then
esac
+
+ if [ $PCRE_JIT = YES ]; then
+ have=NGX_HAVE_PCRE_JIT . auto/have
+ PCRE_CONF_OPT="$PCRE_CONF_OPT --enable-jit"
+ fi
+
else
if [ "$NGX_PLATFORM" != win32 -a `uname -s` != OpenBSD ]; then
@@ -94,7 +98,9 @@ else
ngx_feature_incs="#include <pcre.h>"
ngx_feature_path=
ngx_feature_libs="-lpcre"
- ngx_feature_test="pcre *re; re = pcre_compile(NULL, 0, NULL, 0, NULL)"
+ ngx_feature_test="pcre *re;
+ re = pcre_compile(NULL, 0, NULL, 0, NULL);
+ if (re == NULL) return 1"
. auto/feature
if [ $ngx_found = no ]; then
@@ -157,16 +163,27 @@ else
fi
if [ $ngx_found = yes ]; then
- CORE_DEPS="$CORE_DEPS $REGEX_DEPS"
- CORE_SRCS="$CORE_SRCS $REGEX_SRCS"
CORE_INCS="$CORE_INCS $ngx_feature_path"
CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
PCRE=YES
fi
+
+ if [ $PCRE = YES ]; then
+ ngx_feature="PCRE JIT support"
+ ngx_feature_name="NGX_HAVE_PCRE_JIT"
+ ngx_feature_test="int jit = 0;
+ pcre_config(PCRE_CONFIG_JIT, &jit);
+ if (jit != 1) return 1;"
+ . auto/feature
+
+ if [ $ngx_found = yes ]; then
+ PCRE_JIT=YES
+ fi
+ fi
fi
have=NGX_PCRE . auto/have
- CORE_SRCS="$CORE_SRCS $PCRE_SRCS $REGEX_SRCS"
+ CORE_SRCS="$CORE_SRCS $PCRE_SRCS"
CORE_INCS="$CORE_INCS src/pcre"
CFLAGS="$CFLAGS -DHAVE_CONFIG_H -DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10"
PCRE=YES
diff --git a/usr.sbin/nginx/auto/lib/pcre/make b/usr.sbin/nginx/auto/lib/pcre/make
index 1695b934073..834779b9cce 100644
--- a/usr.sbin/nginx/auto/lib/pcre/make
+++ b/usr.sbin/nginx/auto/lib/pcre/make
@@ -51,7 +51,7 @@ $PCRE/Makefile: $NGX_MAKEFILE
cd $PCRE \\
&& if [ -f Makefile ]; then \$(MAKE) distclean; fi \\
&& CC="\$(CC)" CFLAGS="$PCRE_OPT" \\
- ./configure --disable-shared
+ ./configure --disable-shared $PCRE_CONF_OPT
$PCRE/.libs/libpcre.a: $PCRE/Makefile
cd $PCRE \\
diff --git a/usr.sbin/nginx/auto/modules b/usr.sbin/nginx/auto/modules
index f8d31a3833e..dab660f8733 100644
--- a/usr.sbin/nginx/auto/modules
+++ b/usr.sbin/nginx/auto/modules
@@ -211,9 +211,9 @@ if [ $HTTP_ACCESS = YES ]; then
HTTP_SRCS="$HTTP_SRCS $HTTP_ACCESS_SRCS"
fi
-if [ $HTTP_LIMIT_ZONE = YES ]; then
- HTTP_MODULES="$HTTP_MODULES $HTTP_LIMIT_ZONE_MODULE"
- HTTP_SRCS="$HTTP_SRCS $HTTP_LIMIT_ZONE_SRCS"
+if [ $HTTP_LIMIT_CONN = YES ]; then
+ HTTP_MODULES="$HTTP_MODULES $HTTP_LIMIT_CONN_MODULE"
+ HTTP_SRCS="$HTTP_SRCS $HTTP_LIMIT_CONN_SRCS"
fi
if [ $HTTP_LIMIT_REQ = YES ]; then
@@ -345,6 +345,11 @@ if [ $HTTP_UPSTREAM_IP_HASH = YES ]; then
HTTP_SRCS="$HTTP_SRCS $HTTP_UPSTREAM_IP_HASH_SRCS"
fi
+if [ $HTTP_UPSTREAM_KEEPALIVE = YES ]; then
+ HTTP_MODULES="$HTTP_MODULES $HTTP_UPSTREAM_KEEPALIVE_MODULE"
+ HTTP_SRCS="$HTTP_SRCS $HTTP_UPSTREAM_KEEPALIVE_SRCS"
+fi
+
if [ $HTTP_STUB_STATUS = YES ]; then
have=NGX_STAT_STUB . auto/have
HTTP_MODULES="$HTTP_MODULES ngx_http_stub_status_module"
@@ -392,6 +397,12 @@ if [ $USE_OPENSSL = YES ]; then
CORE_SRCS="$CORE_SRCS $OPENSSL_SRCS"
fi
+if [ $USE_PCRE = YES ]; then
+ modules="$modules $REGEX_MODULE"
+ CORE_DEPS="$CORE_DEPS $REGEX_DEPS"
+ CORE_SRCS="$CORE_SRCS $REGEX_SRCS"
+fi
+
if [ $HTTP = YES ]; then
modules="$modules $HTTP_MODULES $HTTP_FILTER_MODULES \
$HTTP_HEADERS_FILTER_MODULE \
diff --git a/usr.sbin/nginx/auto/options b/usr.sbin/nginx/auto/options
index 6eea8c4a8b8..393be406616 100644
--- a/usr.sbin/nginx/auto/options
+++ b/usr.sbin/nginx/auto/options
@@ -86,7 +86,7 @@ HTTP_UWSGI=YES
HTTP_SCGI=YES
HTTP_PERL=NO
HTTP_MEMCACHED=YES
-HTTP_LIMIT_ZONE=YES
+HTTP_LIMIT_CONN=YES
HTTP_LIMIT_REQ=YES
HTTP_EMPTY_GIF=YES
HTTP_BROWSER=YES
@@ -96,6 +96,7 @@ HTTP_FLV=NO
HTTP_MP4=NO
HTTP_GZIP_STATIC=NO
HTTP_UPSTREAM_IP_HASH=YES
+HTTP_UPSTREAM_KEEPALIVE=YES
# STUB
HTTP_STUB_STATUS=NO
@@ -111,6 +112,8 @@ NGX_ADDONS=
USE_PCRE=NO
PCRE=NONE
PCRE_OPT=
+PCRE_CONF_OPT=
+PCRE_JIT=NO
USE_OPENSSL=NO
OPENSSL=NONE
@@ -143,6 +146,8 @@ NGX_LIBATOMIC=NO
NGX_CPU_CACHE_LINE=
+NGX_POST_CONF_MSG=
+
opt=
for option
@@ -227,11 +232,18 @@ do
--without-http_uwsgi_module) HTTP_UWSGI=NO ;;
--without-http_scgi_module) HTTP_SCGI=NO ;;
--without-http_memcached_module) HTTP_MEMCACHED=NO ;;
- --without-http_limit_zone_module) HTTP_LIMIT_ZONE=NO ;;
+ --without-http_limit_zone_module)
+ HTTP_LIMIT_CONN=NO
+ NGX_POST_CONF_MSG="$NGX_POST_CONF_MSG
+$0: warning: the \"--without-http_limit_zone_module\" option is deprecated, \
+use the \"--without-http_limit_conn_module\" option instead"
+ ;;
+ --without-http_limit_conn_module) HTTP_LIMIT_CONN=NO ;;
--without-http_limit_req_module) HTTP_LIMIT_REQ=NO ;;
--without-http_empty_gif_module) HTTP_EMPTY_GIF=NO ;;
--without-http_browser_module) HTTP_BROWSER=NO ;;
--without-http_upstream_ip_hash_module) HTTP_UPSTREAM_IP_HASH=NO ;;
+ --without-http_upstream_keepalive_module) HTTP_UPSTREAM_KEEPALIVE=NO ;;
--with-http_perl_module) HTTP_PERL=YES ;;
--with-perl_modules_path=*) NGX_PERL_MODULES="$value" ;;
@@ -265,6 +277,7 @@ do
--with-pcre) USE_PCRE=YES ;;
--with-pcre=*) PCRE="$value" ;;
--with-pcre-opt=*) PCRE_OPT="$value" ;;
+ --with-pcre-jit) PCRE_JIT=YES ;;
--with-openssl=*) OPENSSL="$value" ;;
--with-openssl-opt=*) OPENSSL_OPT="$value" ;;
@@ -363,7 +376,7 @@ cat << END
--without-http_uwsgi_module disable ngx_http_uwsgi_module
--without-http_scgi_module disable ngx_http_scgi_module
--without-http_memcached_module disable ngx_http_memcached_module
- --without-http_limit_zone_module disable ngx_http_limit_zone_module
+ --without-http_limit_conn_module disable ngx_http_limit_conn_module
--without-http_limit_req_module disable ngx_http_limit_req_module
--without-http_empty_gif_module disable ngx_http_empty_gif_module
--without-http_browser_module disable ngx_http_browser_module
@@ -412,6 +425,7 @@ cat << END
--with-pcre force PCRE library usage
--with-pcre=DIR set path to PCRE library sources
--with-pcre-opt=OPTIONS set additional build options for PCRE
+ --with-pcre-jit build PCRE with JIT compilation support
--with-md5=DIR set path to md5 library sources
--with-md5-opt=OPTIONS set additional build options for md5
diff --git a/usr.sbin/nginx/auto/os/freebsd b/usr.sbin/nginx/auto/os/freebsd
index 88654ba60fb..6aa823f9250 100644
--- a/usr.sbin/nginx/auto/os/freebsd
+++ b/usr.sbin/nginx/auto/os/freebsd
@@ -134,3 +134,11 @@ END
exit 1
fi
fi
+
+
+# cpuset_setaffinity()
+
+if [ $version -ge 701000 ]; then
+ echo " + cpuset_setaffinity() found"
+ have=NGX_HAVE_CPUSET_SETAFFINITY . auto/have
+fi
diff --git a/usr.sbin/nginx/auto/os/linux b/usr.sbin/nginx/auto/os/linux
index 0b2173cae9c..c506d3dc3ad 100644
--- a/usr.sbin/nginx/auto/os/linux
+++ b/usr.sbin/nginx/auto/os/linux
@@ -52,7 +52,7 @@ ngx_feature_run=yes
ngx_feature_incs="#include <sys/epoll.h>"
ngx_feature_path=
ngx_feature_libs=
-ngx_feature_test="int efd = 0, fd = 1, n;
+ngx_feature_test="int efd = 0;
struct epoll_event ee;
ee.events = EPOLLIN|EPOLLOUT|EPOLLET;
ee.data.ptr = NULL;
@@ -128,8 +128,9 @@ ngx_feature_run=no
ngx_feature_incs="#include <sched.h>"
ngx_feature_path=
ngx_feature_libs=
-ngx_feature_test="long mask = 0;
- sched_setaffinity(0, 32, (cpu_set_t *) &mask)"
+ngx_feature_test="cpu_set_t mask;
+ CPU_ZERO(&mask);
+ sched_setaffinity(0, sizeof(cpu_set_t), &mask)"
. auto/feature
@@ -142,7 +143,7 @@ ngx_feature_incs="#include <crypt.h>"
ngx_feature_path=
ngx_feature_libs=-lcrypt
ngx_feature_test="struct crypt_data cd;
- crypt_r(NULL, NULL, &cd);"
+ crypt_r(\"key\", \"salt\", &cd);"
. auto/feature
diff --git a/usr.sbin/nginx/auto/os/solaris b/usr.sbin/nginx/auto/os/solaris
index 16da4b3fd31..d39df0bf713 100644
--- a/usr.sbin/nginx/auto/os/solaris
+++ b/usr.sbin/nginx/auto/os/solaris
@@ -35,7 +35,8 @@ ngx_feature_path=
ngx_feature_libs="-lsendfile"
ngx_feature_test="int fd = 1; sendfilevec_t vec[1];
size_t sent; ssize_t n;
- n = sendfilev(fd, vec, 1, &sent)"
+ n = sendfilev(fd, vec, 1, &sent);
+ if (n == -1) return 1"
. auto/feature
diff --git a/usr.sbin/nginx/auto/sources b/usr.sbin/nginx/auto/sources
index 2036776cf3e..d95f3badffe 100644
--- a/usr.sbin/nginx/auto/sources
+++ b/usr.sbin/nginx/auto/sources
@@ -70,6 +70,7 @@ CORE_SRCS="src/core/nginx.c \
src/core/ngx_crypt.c"
+REGEX_MODULE=ngx_regex_module
REGEX_DEPS=src/core/ngx_regex.h
REGEX_SRCS=src/core/ngx_regex.c
@@ -80,6 +81,7 @@ PCRE_SRCS="src/pcre/pcre_chartables.c \
src/pcre/pcre_globals.c \
src/pcre/pcre_newline.c \
src/pcre/pcre_ord2utf8.c \
+ src/pcre/pcre_study.c \
src/pcre/pcre_tables.c \
src/pcre/pcre_ucd.c \
src/pcre/pcre_valid_utf8.c \
@@ -155,6 +157,7 @@ UNIX_DEPS="$CORE_DEPS $EVENT_DEPS \
src/os/unix/ngx_channel.h \
src/os/unix/ngx_shmem.h \
src/os/unix/ngx_process.h \
+ src/os/unix/ngx_setaffinity.h \
src/os/unix/ngx_setproctitle.h \
src/os/unix/ngx_atomic.h \
src/os/unix/ngx_gcc_atomic_x86.h \
@@ -189,6 +192,7 @@ UNIX_SRCS="$CORE_SRCS $EVENT_SRCS \
src/os/unix/ngx_shmem.c \
src/os/unix/ngx_process.c \
src/os/unix/ngx_daemon.c \
+ src/os/unix/ngx_setaffinity.c \
src/os/unix/ngx_setproctitle.c \
src/os/unix/ngx_posix_init.c \
src/os/unix/ngx_user.c \
@@ -447,8 +451,8 @@ HTTP_MEMCACHED_MODULE=ngx_http_memcached_module
HTTP_MEMCACHED_SRCS=src/http/modules/ngx_http_memcached_module.c
-HTTP_LIMIT_ZONE_MODULE=ngx_http_limit_zone_module
-HTTP_LIMIT_ZONE_SRCS=src/http/modules/ngx_http_limit_zone_module.c
+HTTP_LIMIT_CONN_MODULE=ngx_http_limit_conn_module
+HTTP_LIMIT_CONN_SRCS=src/http/modules/ngx_http_limit_conn_module.c
HTTP_LIMIT_REQ_MODULE=ngx_http_limit_req_module
@@ -487,6 +491,11 @@ HTTP_UPSTREAM_IP_HASH_MODULE=ngx_http_upstream_ip_hash_module
HTTP_UPSTREAM_IP_HASH_SRCS=src/http/modules/ngx_http_upstream_ip_hash_module.c
+HTTP_UPSTREAM_KEEPALIVE_MODULE=ngx_http_upstream_keepalive_module
+HTTP_UPSTREAM_KEEPALIVE_SRCS=" \
+ src/http/modules/ngx_http_upstream_keepalive_module.c"
+
+
MAIL_INCS="src/mail"
MAIL_DEPS="src/mail/ngx_mail.h"
diff --git a/usr.sbin/nginx/auto/summary b/usr.sbin/nginx/auto/summary
index f7f32a442a4..dcebec9f0fe 100644
--- a/usr.sbin/nginx/auto/summary
+++ b/usr.sbin/nginx/auto/summary
@@ -112,3 +112,5 @@ fi
if [ $HTTP_SCGI = YES ]; then
echo " nginx http scgi temporary files: \"$NGX_HTTP_SCGI_TEMP_PATH\""
fi
+
+echo "$NGX_POST_CONF_MSG"
diff --git a/usr.sbin/nginx/auto/types/sizeof b/usr.sbin/nginx/auto/types/sizeof
index e84a0905ef9..e1d405c6500 100644
--- a/usr.sbin/nginx/auto/types/sizeof
+++ b/usr.sbin/nginx/auto/types/sizeof
@@ -20,12 +20,13 @@ cat << END > $NGX_AUTOTEST.c
#include <sys/time.h>
$NGX_INCLUDE_UNISTD_H
#include <signal.h>
+#include <stdio.h>
#include <sys/resource.h>
$NGX_INCLUDE_INTTYPES_H
$NGX_INCLUDE_AUTO_CONFIG_H
int main() {
- printf("%d", sizeof($ngx_type));
+ printf("%d", (int) sizeof($ngx_type));
return 0;
}
diff --git a/usr.sbin/nginx/auto/types/typedef b/usr.sbin/nginx/auto/types/typedef
index f121e8fc2ea..d81229331fd 100644
--- a/usr.sbin/nginx/auto/types/typedef
+++ b/usr.sbin/nginx/auto/types/typedef
@@ -29,7 +29,7 @@ $NGX_INCLUDE_INTTYPES_H
int main() {
$ngx_try i = 0;
- return 0;
+ return (int) i;
}
END
diff --git a/usr.sbin/nginx/auto/types/uintptr_t b/usr.sbin/nginx/auto/types/uintptr_t
index 07f7e7d7dba..2f19080352b 100644
--- a/usr.sbin/nginx/auto/types/uintptr_t
+++ b/usr.sbin/nginx/auto/types/uintptr_t
@@ -4,8 +4,8 @@
echo $ngx_n "checking for uintptr_t ...$ngx_c"
-echo >> $NGX_ERR
-echo "checking for uintptr_t" >> $NGX_ERR
+echo >> $NGX_AUTOCONF_ERR
+echo "checking for uintptr_t" >> $NGX_AUTOCONF_ERR
found=no
@@ -16,12 +16,15 @@ $NGX_INTTYPES_H
int main() {
uintptr_t i = 0;
- return 0;
+ return (int) i;
}
END
-eval "$CC -o $NGX_AUTOTEST $NGX_AUTOTEST.c >> $NGX_ERR 2>&1"
+ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS \
+ -o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_LD_OPT"
+
+eval "$ngx_test >> $NGX_AUTOCONF_ERR 2>&1"
if [ -x $NGX_AUTOTEST ]; then
echo " uintptr_t found"
diff --git a/usr.sbin/nginx/auto/unix b/usr.sbin/nginx/auto/unix
index 78f82593d2f..783219e2db7 100755
--- a/usr.sbin/nginx/auto/unix
+++ b/usr.sbin/nginx/auto/unix
@@ -33,12 +33,12 @@ ngx_feature_run=no
ngx_feature_incs="#include <poll.h>"
ngx_feature_path=
ngx_feature_libs=
-ngx_feature_test="int n, dp; struct pollfd pl;
- dp = 0;
+ngx_feature_test="int n; struct pollfd pl;
pl.fd = 0;
pl.events = 0;
pl.revents = 0;
- n = poll(&pl, 1, 0)"
+ n = poll(&pl, 1, 0);
+ if (n == -1) return 1"
. auto/feature
if [ $ngx_found = no ]; then
@@ -57,7 +57,8 @@ ngx_feature_test="int n, dp; struct dvpoll dvp;
dvp.dp_fds = NULL;
dvp.dp_nfds = 0;
dvp.dp_timeout = 0;
- n = ioctl(dp, DP_POLL, &dvp)"
+ n = ioctl(dp, DP_POLL, &dvp);
+ if (n == -1) return 1"
. auto/feature
if [ $ngx_found = yes ]; then
@@ -237,7 +238,7 @@ ngx_feature_incs="$NGX_INCLUDE_SYS_PARAM_H
ngx_feature_path=
ngx_feature_libs=
ngx_feature_test="struct statfs fs;
- statfs(NULL, &fs);"
+ statfs(\".\", &fs);"
. auto/feature
@@ -249,7 +250,7 @@ ngx_feature_incs="#include <sys/types.h>
ngx_feature_path=
ngx_feature_libs=
ngx_feature_test="struct statvfs fs;
- statvfs(NULL, &fs);"
+ statvfs(\".\", &fs);"
. auto/feature
@@ -329,6 +330,38 @@ ngx_feature_test="setsockopt(0, IPPROTO_TCP, TCP_DEFER_ACCEPT, NULL, 0)"
. auto/feature
+ngx_feature="TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_KEEPCNT"
+ngx_feature_name="NGX_HAVE_KEEPALIVE_TUNABLE"
+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_KEEPIDLE, NULL, 0);
+ setsockopt(0, IPPROTO_TCP, TCP_KEEPINTVL, NULL, 0);
+ setsockopt(0, IPPROTO_TCP, TCP_KEEPCNT, NULL, 0)"
+. auto/feature
+
+
+ngx_feature="TCP_INFO"
+ngx_feature_name="NGX_HAVE_TCP_INFO"
+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="socklen_t optlen = sizeof(struct tcp_info);
+ struct tcp_info ti;
+ ti.tcpi_rtt = 0;
+ ti.tcpi_rttvar = 0;
+ ti.tcpi_snd_cwnd = 0;
+ ti.tcpi_rcv_space = 0;
+ getsockopt(0, IPPROTO_TCP, TCP_INFO, &ti, &optlen)"
+. auto/feature
+
+
ngx_feature="accept4()"
ngx_feature_name="NGX_HAVE_ACCEPT4"
ngx_feature_run=no
@@ -467,7 +500,7 @@ fi
ngx_feature="setproctitle()"
ngx_feature_name="NGX_HAVE_SETPROCTITLE"
ngx_feature_run=no
-ngx_feature_incs=
+ngx_feature_incs="#include <stdlib.h>"
ngx_feature_path=
ngx_feature_libs=$NGX_SETPROCTITLE_LIB
ngx_feature_test="setproctitle(\"test\");"
@@ -480,7 +513,8 @@ ngx_feature_run=no
ngx_feature_incs=
ngx_feature_path=
ngx_feature_libs=
-ngx_feature_test="char buf[1]; ssize_t n; n = pread(0, buf, 1, 0)"
+ngx_feature_test="char buf[1]; ssize_t n; n = pread(0, buf, 1, 0);
+ if (n == -1) return 1"
. auto/feature
@@ -490,7 +524,8 @@ ngx_feature_run=no
ngx_feature_incs=
ngx_feature_path=
ngx_feature_libs=
-ngx_feature_test="char buf[1]; ssize_t n; n = pwrite(1, buf, 1, 0)"
+ngx_feature_test="char buf[1]; ssize_t n; n = pwrite(1, buf, 1, 0);
+ if (n == -1) return 1"
. auto/feature
@@ -564,17 +599,20 @@ ngx_feature_run=no
ngx_feature_incs="#include <stdlib.h>"
ngx_feature_path=
ngx_feature_libs=
-ngx_feature_test="void *p; int n; n = posix_memalign(&p, 4096, 4096)"
+ngx_feature_test="void *p; int n; n = posix_memalign(&p, 4096, 4096);
+ if (n != 0) return 1"
. auto/feature
ngx_feature="memalign()"
ngx_feature_name="NGX_HAVE_MEMALIGN"
ngx_feature_run=no
-ngx_feature_incs="#include <stdlib.h>"
+ngx_feature_incs="#include <stdlib.h>
+ #include <malloc.h>"
ngx_feature_path=
ngx_feature_libs=
-ngx_feature_test="void *p; p = memalign(4096, 4096)"
+ngx_feature_test="void *p; p = memalign(4096, 4096);
+ if (p == NULL) return 1"
. auto/feature
@@ -661,10 +699,12 @@ fi
ngx_feature="struct msghdr.msg_control"
ngx_feature_name="NGX_HAVE_MSGHDR_MSG_CONTROL"
ngx_feature_run=no
-ngx_feature_incs="#include <sys/socket.h>"
+ngx_feature_incs="#include <sys/socket.h>
+ #include <stdio.h>"
ngx_feature_path=
ngx_feature_libs=
-ngx_feature_test="struct msghdr msg; msg.msg_control = NULL"
+ngx_feature_test="struct msghdr msg;
+ printf(\"%d\", (int) sizeof(msg.msg_control))"
. auto/feature
@@ -672,40 +712,47 @@ ngx_feature="ioctl(FIONBIO)"
ngx_feature_name="NGX_HAVE_FIONBIO"
ngx_feature_run=no
ngx_feature_incs="#include <sys/ioctl.h>
+ #include <stdio.h>
$NGX_INCLUDE_SYS_FILIO_H"
ngx_feature_path=
ngx_feature_libs=
-ngx_feature_test="int i; i = FIONBIO"
+ngx_feature_test="int i = FIONBIO; printf(\"%d\", i)"
. auto/feature
ngx_feature="struct tm.tm_gmtoff"
ngx_feature_name="NGX_HAVE_GMTOFF"
ngx_feature_run=no
-ngx_feature_incs="#include <time.h>"
+ngx_feature_incs="#include <time.h>
+ #include <stdio.h>"
ngx_feature_path=
ngx_feature_libs=
-ngx_feature_test="struct tm tm; tm.tm_gmtoff = 0"
+ngx_feature_test="struct tm tm; tm.tm_gmtoff = 0;
+ printf(\"%d\", (int) tm.tm_gmtoff)"
. auto/feature
ngx_feature="struct dirent.d_namlen"
ngx_feature_name="NGX_HAVE_D_NAMLEN"
ngx_feature_run=no
-ngx_feature_incs="#include <dirent.h>"
+ngx_feature_incs="#include <dirent.h>
+ #include <stdio.h>"
ngx_feature_path=
ngx_feature_libs=
-ngx_feature_test="struct dirent dir; dir.d_namlen = 0"
+ngx_feature_test="struct dirent dir; dir.d_namlen = 0;
+ printf(\"%d\", (int) dir.d_namlen)"
. auto/feature
ngx_feature="struct dirent.d_type"
ngx_feature_name="NGX_HAVE_D_TYPE"
ngx_feature_run=no
-ngx_feature_incs="#include <dirent.h>"
+ngx_feature_incs="#include <dirent.h>
+ #include <stdio.h>"
ngx_feature_path=
ngx_feature_libs=
-ngx_feature_test="struct dirent dir; dir.d_type = DT_REG"
+ngx_feature_test="struct dirent dir; dir.d_type = DT_REG;
+ printf(\"%d\", (int) dir.d_type)"
. auto/feature
@@ -717,3 +764,17 @@ ngx_feature_path=
ngx_feature_libs=
ngx_feature_test="sysconf(_SC_NPROCESSORS_ONLN)"
. auto/feature
+
+
+ngx_feature="openat(), fstatat()"
+ngx_feature_name="NGX_HAVE_OPENAT"
+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="struct stat sb;
+ openat(AT_FDCWD, \".\", O_RDONLY|O_NOFOLLOW);
+ fstatat(AT_FDCWD, \".\", &sb, AT_SYMLINK_NOFOLLOW);"
+. auto/feature
diff --git a/usr.sbin/nginx/conf/fastcgi.conf b/usr.sbin/nginx/conf/fastcgi.conf
index fab09eb2455..ac9ff92049f 100644
--- a/usr.sbin/nginx/conf/fastcgi.conf
+++ b/usr.sbin/nginx/conf/fastcgi.conf
@@ -10,6 +10,7 @@ fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
+fastcgi_param HTTPS $https if_not_empty;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
diff --git a/usr.sbin/nginx/conf/fastcgi_params b/usr.sbin/nginx/conf/fastcgi_params
index 201c686e251..71e2c2e3bed 100644
--- a/usr.sbin/nginx/conf/fastcgi_params
+++ b/usr.sbin/nginx/conf/fastcgi_params
@@ -9,6 +9,7 @@ fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
+fastcgi_param HTTPS $https if_not_empty;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
diff --git a/usr.sbin/nginx/conf/scgi_params b/usr.sbin/nginx/conf/scgi_params
index 257167eb7b3..47348ca381c 100644
--- a/usr.sbin/nginx/conf/scgi_params
+++ b/usr.sbin/nginx/conf/scgi_params
@@ -8,6 +8,7 @@ scgi_param DOCUMENT_URI $document_uri;
scgi_param DOCUMENT_ROOT $document_root;
scgi_param SCGI 1;
scgi_param SERVER_PROTOCOL $server_protocol;
+scgi_param HTTPS $https if_not_empty;
scgi_param REMOTE_ADDR $remote_addr;
scgi_param REMOTE_PORT $remote_port;
diff --git a/usr.sbin/nginx/conf/uwsgi_params b/usr.sbin/nginx/conf/uwsgi_params
index b57e8e78ea2..f539451b6f5 100644
--- a/usr.sbin/nginx/conf/uwsgi_params
+++ b/usr.sbin/nginx/conf/uwsgi_params
@@ -8,6 +8,7 @@ uwsgi_param REQUEST_URI $request_uri;
uwsgi_param PATH_INFO $document_uri;
uwsgi_param DOCUMENT_ROOT $document_root;
uwsgi_param SERVER_PROTOCOL $server_protocol;
+uwsgi_param HTTPS $https if_not_empty;
uwsgi_param REMOTE_ADDR $remote_addr;
uwsgi_param REMOTE_PORT $remote_port;
diff --git a/usr.sbin/nginx/man/nginx.8 b/usr.sbin/nginx/man/nginx.8
index 9d7fc1e9254..229dca91613 100644
--- a/usr.sbin/nginx/man/nginx.8
+++ b/usr.sbin/nginx/man/nginx.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: nginx.8,v 1.5 2012/04/05 10:28:03 sthen Exp $
+.\" $OpenBSD: nginx.8,v 1.6 2012/05/13 09:14:58 robert Exp $
.\"
.\" Copyright (c) 2010 Sergey A. Osokin
.\" Copyright (c) 2011,2012 Nginx, Inc.
@@ -26,7 +26,7 @@
.\" SUCH DAMAGE.
.\"
.\"
-.Dd $Mdocdate: April 5 2012 $
+.Dd $Mdocdate: May 13 2012 $
.Dt NGINX 8
.Os
.Sh NAME
@@ -195,9 +195,7 @@ nginx -t -c ~/mynginx.conf \e
.\"Xr nginx.conf 5
.\"Pp
Documentation at
-.Pa http://nginx.org/
-and
-.Pa http://sysoev.ru/nginx/ .
+.Pa http://nginx.org/en/docs/ .
.Pp
For questions and technical support, please refer to
.Pa http://nginx.org/en/support.html .
diff --git a/usr.sbin/nginx/src/core/nginx.c b/usr.sbin/nginx/src/core/nginx.c
index bb539e55a13..a59de2dbedf 100644
--- a/usr.sbin/nginx/src/core/nginx.c
+++ b/usr.sbin/nginx/src/core/nginx.c
@@ -204,9 +204,7 @@ main(int argc, char *const *argv)
ngx_cycle_t *cycle, init_cycle;
ngx_core_conf_t *ccf;
-#if (NGX_FREEBSD)
ngx_debug_init();
-#endif
if (ngx_strerror_init() != NGX_OK) {
return 1;
@@ -653,7 +651,7 @@ ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv)
if (ngx_rename_file(ccf->oldpid.data, ccf->pid.data) != NGX_OK) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
ngx_rename_file_n " %s back to %s failed after "
- "the try to execute the new binary process \"%s\"",
+ "an attempt to execute new binary process \"%s\"",
ccf->oldpid.data, ccf->pid.data, argv[0]);
}
}
@@ -991,15 +989,15 @@ ngx_core_module_init_conf(ngx_cycle_t *cycle, void *conf)
ngx_conf_init_value(ccf->worker_processes, 1);
ngx_conf_init_value(ccf->debug_points, 0);
-#if (NGX_HAVE_SCHED_SETAFFINITY)
+#if (NGX_HAVE_CPU_AFFINITY)
if (ccf->cpu_affinity_n
&& ccf->cpu_affinity_n != 1
&& ccf->cpu_affinity_n != (ngx_uint_t) ccf->worker_processes)
{
ngx_log_error(NGX_LOG_WARN, cycle->log, 0,
- "number of the \"worker_processes\" is not equal to "
- "the number of the \"worker_cpu_affinity\" mask, "
+ "the number of \"worker_processes\" is not equal to "
+ "the number of \"worker_cpu_affinity\" masks, "
"using last mask for remaining worker processes");
}
@@ -1250,11 +1248,11 @@ ngx_set_priority(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
static char *
ngx_set_cpu_affinity(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
-#if (NGX_HAVE_SCHED_SETAFFINITY)
+#if (NGX_HAVE_CPU_AFFINITY)
ngx_core_conf_t *ccf = conf;
u_char ch;
- u_long *mask;
+ uint64_t *mask;
ngx_str_t *value;
ngx_uint_t i, n;
@@ -1262,7 +1260,7 @@ ngx_set_cpu_affinity(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return "is duplicate";
}
- mask = ngx_palloc(cf->pool, (cf->args->nelts - 1) * sizeof(long));
+ mask = ngx_palloc(cf->pool, (cf->args->nelts - 1) * sizeof(uint64_t));
if (mask == NULL) {
return NGX_CONF_ERROR;
}
@@ -1274,9 +1272,9 @@ ngx_set_cpu_affinity(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
for (n = 1; n < cf->args->nelts; n++) {
- if (value[n].len > 32) {
+ if (value[n].len > 64) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "\"worker_cpu_affinity\" supports up to 32 CPU only");
+ "\"worker_cpu_affinity\" supports up to 64 CPUs only");
return NGX_CONF_ERROR;
}
@@ -1319,7 +1317,7 @@ ngx_set_cpu_affinity(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}
-u_long
+uint64_t
ngx_get_cpu_affinity(ngx_uint_t n)
{
ngx_core_conf_t *ccf;
diff --git a/usr.sbin/nginx/src/core/nginx.h b/usr.sbin/nginx/src/core/nginx.h
index fdc2c925cd8..ca777f6d5ac 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 1000015
-#define NGINX_VERSION "1.0.15"
+#define nginx_version 1002000
+#define NGINX_VERSION "1.2.0"
#define NGINX_VER "nginx/" NGINX_VERSION
#define NGINX_VAR "NGINX"
diff --git a/usr.sbin/nginx/src/core/ngx_buf.c b/usr.sbin/nginx/src/core/ngx_buf.c
index 817a96cda7c..835c76ced6b 100644
--- a/usr.sbin/nginx/src/core/ngx_buf.c
+++ b/usr.sbin/nginx/src/core/ngx_buf.c
@@ -181,7 +181,7 @@ ngx_chain_get_free_buf(ngx_pool_t *p, ngx_chain_t **free)
void
-ngx_chain_update_chains(ngx_chain_t **free, ngx_chain_t **busy,
+ngx_chain_update_chains(ngx_pool_t *p, ngx_chain_t **free, ngx_chain_t **busy,
ngx_chain_t **out, ngx_buf_tag_t tag)
{
ngx_chain_t *cl;
@@ -198,19 +198,21 @@ ngx_chain_update_chains(ngx_chain_t **free, ngx_chain_t **busy,
*out = NULL;
while (*busy) {
- if (ngx_buf_size((*busy)->buf) != 0) {
+ cl = *busy;
+
+ if (ngx_buf_size(cl->buf) != 0) {
break;
}
- if ((*busy)->buf->tag != tag) {
- *busy = (*busy)->next;
+ if (cl->buf->tag != tag) {
+ *busy = cl->next;
+ ngx_free_chain(p, cl);
continue;
}
- (*busy)->buf->pos = (*busy)->buf->start;
- (*busy)->buf->last = (*busy)->buf->start;
+ cl->buf->pos = cl->buf->start;
+ cl->buf->last = cl->buf->start;
- cl = *busy;
*busy = cl->next;
cl->next = *free;
*free = cl;
diff --git a/usr.sbin/nginx/src/core/ngx_buf.h b/usr.sbin/nginx/src/core/ngx_buf.h
index 39f31b34f2c..ffc53109433 100644
--- a/usr.sbin/nginx/src/core/ngx_buf.h
+++ b/usr.sbin/nginx/src/core/ngx_buf.h
@@ -155,8 +155,8 @@ ngx_int_t ngx_chain_writer(void *ctx, ngx_chain_t *in);
ngx_int_t ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain,
ngx_chain_t *in);
ngx_chain_t *ngx_chain_get_free_buf(ngx_pool_t *p, ngx_chain_t **free);
-void ngx_chain_update_chains(ngx_chain_t **free, ngx_chain_t **busy,
- ngx_chain_t **out, ngx_buf_tag_t tag);
+void ngx_chain_update_chains(ngx_pool_t *p, ngx_chain_t **free,
+ ngx_chain_t **busy, ngx_chain_t **out, ngx_buf_tag_t tag);
#endif /* _NGX_BUF_H_INCLUDED_ */
diff --git a/usr.sbin/nginx/src/core/ngx_conf_file.c b/usr.sbin/nginx/src/core/ngx_conf_file.c
index 83265014127..892fa4719a8 100644
--- a/usr.sbin/nginx/src/core/ngx_conf_file.c
+++ b/usr.sbin/nginx/src/core/ngx_conf_file.c
@@ -465,7 +465,7 @@ ngx_conf_read_token(ngx_conf_t *cf)
if (cf->conf_file->file.offset >= file_size) {
- if (cf->args->nelts > 0) {
+ if (cf->args->nelts > 0 || !last_space) {
if (cf->conf_file->file.fd == NGX_INVALID_FILE) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -1295,10 +1295,6 @@ ngx_conf_set_msec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return "invalid value";
}
- if (*msp == (ngx_msec_t) NGX_PARSE_LARGE_TIME) {
- return "value must be less than 597 hours";
- }
-
if (cmd->post) {
post = cmd->post;
return post->post_handler(cf, post, msp);
@@ -1326,14 +1322,10 @@ ngx_conf_set_sec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
value = cf->args->elts;
*sp = ngx_parse_time(&value[1], 1);
- if (*sp == NGX_ERROR) {
+ if (*sp == (time_t) NGX_ERROR) {
return "invalid value";
}
- if (*sp == NGX_PARSE_LARGE_TIME) {
- return "value must be less than 68 years";
- }
-
if (cmd->post) {
post = cmd->post;
return post->post_handler(cf, post, sp);
@@ -1489,7 +1481,8 @@ ngx_conf_check_num_bounds(ngx_conf_t *cf, void *post, void *data)
}
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "value must be equal or more than %i", bounds->low);
+ "value must be equal to or greater than %i",
+ bounds->low);
return NGX_CONF_ERROR;
}
diff --git a/usr.sbin/nginx/src/core/ngx_conf_file.h b/usr.sbin/nginx/src/core/ngx_conf_file.h
index e92668cd465..4b87f1aad48 100644
--- a/usr.sbin/nginx/src/core/ngx_conf_file.h
+++ b/usr.sbin/nginx/src/core/ngx_conf_file.h
@@ -14,7 +14,7 @@
/*
- * AAAA number of agruments
+ * AAAA number of arguments
* FF command flags
* TT command type, i.e. HTTP "location" or "server" command
*/
diff --git a/usr.sbin/nginx/src/core/ngx_connection.c b/usr.sbin/nginx/src/core/ngx_connection.c
index b16c5572086..ba1b3f9e2bc 100644
--- a/usr.sbin/nginx/src/core/ngx_connection.c
+++ b/usr.sbin/nginx/src/core/ngx_connection.c
@@ -463,6 +463,7 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle)
void
ngx_configure_listening_sockets(ngx_cycle_t *cycle)
{
+ int keepalive;
ngx_uint_t i;
ngx_listening_t *ls;
@@ -500,6 +501,56 @@ ngx_configure_listening_sockets(ngx_cycle_t *cycle)
}
}
+ if (ls[i].keepalive) {
+ keepalive = (ls[i].keepalive == 1) ? 1 : 0;
+
+ if (setsockopt(ls[i].fd, SOL_SOCKET, SO_KEEPALIVE,
+ (const void *) &keepalive, 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);
+ }
+ }
+
+#if (NGX_HAVE_KEEPALIVE_TUNABLE)
+
+ if (ls[i].keepidle) {
+ if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_KEEPIDLE,
+ (const void *) &ls[i].keepidle, 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);
+ }
+ }
+
+ if (ls[i].keepintvl) {
+ if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_KEEPINTVL,
+ (const void *) &ls[i].keepintvl, 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);
+ }
+ }
+
+ if (ls[i].keepcnt) {
+ if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_KEEPCNT,
+ (const void *) &ls[i].keepcnt, sizeof(int))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+ "setsockopt(TCP_KEEPCNT, %d) %V failed, ignored",
+ ls[i].keepcnt, &ls[i].addr_text);
+ }
+ }
+
+#endif
+
#if (NGX_HAVE_SETFIB)
if (ls[i].setfib != -1) {
if (setsockopt(ls[i].fd, SOL_SOCKET, SO_SETFIB,
@@ -657,7 +708,7 @@ ngx_close_listening_sockets(ngx_cycle_t *cycle)
/*
* it seems that Linux-2.6.x OpenVZ sends events
* for closed shared listening sockets unless
- * the events was explicity deleted
+ * the events was explicitly deleted
*/
ngx_del_event(c->read, NGX_READ_EVENT, 0);
diff --git a/usr.sbin/nginx/src/core/ngx_connection.h b/usr.sbin/nginx/src/core/ngx_connection.h
index 928d661c0a5..34af12e4f34 100644
--- a/usr.sbin/nginx/src/core/ngx_connection.h
+++ b/usr.sbin/nginx/src/core/ngx_connection.h
@@ -28,6 +28,11 @@ struct ngx_listening_s {
int backlog;
int rcvbuf;
int sndbuf;
+#if (NGX_HAVE_KEEPALIVE_TUNABLE)
+ int keepidle;
+ int keepintvl;
+ int keepcnt;
+#endif
/* handler of accepted connection */
ngx_connection_handler_pt handler;
@@ -61,6 +66,7 @@ struct ngx_listening_s {
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
unsigned ipv6only:2;
#endif
+ unsigned keepalive:2;
#if (NGX_HAVE_DEFERRED_ACCEPT)
unsigned deferred_accept:1;
diff --git a/usr.sbin/nginx/src/core/ngx_core.h b/usr.sbin/nginx/src/core/ngx_core.h
index 1ae55163d53..435ce64e7bb 100644
--- a/usr.sbin/nginx/src/core/ngx_core.h
+++ b/usr.sbin/nginx/src/core/ngx_core.h
@@ -91,5 +91,10 @@ typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c);
void ngx_cpuinfo(void);
+#if (NGX_HAVE_OPENAT)
+#define NGX_DISABLE_SYMLINKS_OFF 0
+#define NGX_DISABLE_SYMLINKS_ON 1
+#define NGX_DISABLE_SYMLINKS_NOTOWNER 2
+#endif
#endif /* _NGX_CORE_H_INCLUDED_ */
diff --git a/usr.sbin/nginx/src/core/ngx_cycle.c b/usr.sbin/nginx/src/core/ngx_cycle.c
index a706138203e..4b04d320c1c 100644
--- a/usr.sbin/nginx/src/core/ngx_cycle.c
+++ b/usr.sbin/nginx/src/core/ngx_cycle.c
@@ -953,7 +953,7 @@ ngx_init_zone_pool(ngx_cycle_t *cycle, ngx_shm_zone_t *zn)
#endif
- if (ngx_shmtx_create(&sp->mutex, (void *) &sp->lock, file) != NGX_OK) {
+ if (ngx_shmtx_create(&sp->mutex, &sp->lock, file) != NGX_OK) {
return NGX_ERROR;
}
diff --git a/usr.sbin/nginx/src/core/ngx_cycle.h b/usr.sbin/nginx/src/core/ngx_cycle.h
index dbc6e195e93..551b6288ec0 100644
--- a/usr.sbin/nginx/src/core/ngx_cycle.h
+++ b/usr.sbin/nginx/src/core/ngx_cycle.h
@@ -86,7 +86,7 @@ typedef struct {
int priority;
ngx_uint_t cpu_affinity_n;
- u_long *cpu_affinity;
+ uint64_t *cpu_affinity;
char *username;
ngx_uid_t user;
@@ -124,7 +124,7 @@ ngx_int_t ngx_signal_process(ngx_cycle_t *cycle, char *sig);
void ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user);
char **ngx_set_environment(ngx_cycle_t *cycle, ngx_uint_t *last);
ngx_pid_t ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv);
-u_long ngx_get_cpu_affinity(ngx_uint_t n);
+uint64_t ngx_get_cpu_affinity(ngx_uint_t n);
ngx_shm_zone_t *ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name,
size_t size, void *tag);
diff --git a/usr.sbin/nginx/src/core/ngx_file.c b/usr.sbin/nginx/src/core/ngx_file.c
index 56d5a2aa75c..e37f5f57f1b 100644
--- a/usr.sbin/nginx/src/core/ngx_file.c
+++ b/usr.sbin/nginx/src/core/ngx_file.c
@@ -820,7 +820,7 @@ failed:
* reallocated if ctx->alloc is nonzero
*
* ctx->alloc - a size of data structure that is allocated at every level
- * and is initilialized by ctx->init_handler()
+ * and is initialized by ctx->init_handler()
*
* ctx->log - a log
*
diff --git a/usr.sbin/nginx/src/core/ngx_inet.c b/usr.sbin/nginx/src/core/ngx_inet.c
index 2785c8c8cf6..d2bbbfb58bb 100644
--- a/usr.sbin/nginx/src/core/ngx_inet.c
+++ b/usr.sbin/nginx/src/core/ngx_inet.c
@@ -44,11 +44,7 @@ ngx_inet_addr(u_char *text, size_t len)
return INADDR_NONE;
}
- if (n != 3) {
- return INADDR_NONE;
- }
-
- if (octet < 256) {
+ if (n == 3 && octet < 256) {
addr = (addr << 8) + octet;
return htonl(addr);
}
@@ -407,6 +403,10 @@ ngx_ptocidr(ngx_str_t *text, ngx_cidr_t *cidr)
#if (NGX_HAVE_INET6)
case AF_INET6:
+ if (shift > 128) {
+ return NGX_ERROR;
+ }
+
addr = cidr->u.in6.addr.s6_addr;
mask = cidr->u.in6.mask.s6_addr;
rc = NGX_OK;
@@ -416,7 +416,7 @@ ngx_ptocidr(ngx_str_t *text, ngx_cidr_t *cidr)
s = (shift > 8) ? 8 : shift;
shift -= s;
- mask[i] = (u_char) (0 - (1 << (8 - s)));
+ mask[i] = (u_char) (0xffu << (8 - s));
if (addr[i] != (addr[i] & mask[i])) {
rc = NGX_DONE;
@@ -428,9 +428,12 @@ ngx_ptocidr(ngx_str_t *text, ngx_cidr_t *cidr)
#endif
default: /* AF_INET */
+ if (shift > 32) {
+ return NGX_ERROR;
+ }
if (shift) {
- cidr->u.in.mask = htonl((ngx_uint_t) (0 - (1 << (32 - shift))));
+ cidr->u.in.mask = htonl((uint32_t) (0xffffffffu << (32 - shift)));
} else {
/* x86 compilers use a shl instruction that shifts by modulo 32 */
@@ -459,7 +462,7 @@ ngx_parse_addr(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text, size_t len)
struct sockaddr_in6 *sin6;
/*
- * prevent MSVC8 waring:
+ * prevent MSVC8 warning:
* potentially uninitialized local variable 'inaddr6' used
*/
ngx_memzero(inaddr6.s6_addr, sizeof(struct in6_addr));
diff --git a/usr.sbin/nginx/src/core/ngx_murmurhash.h b/usr.sbin/nginx/src/core/ngx_murmurhash.h
index 2b2b70d6ccf..54e867d303a 100644
--- a/usr.sbin/nginx/src/core/ngx_murmurhash.h
+++ b/usr.sbin/nginx/src/core/ngx_murmurhash.h
@@ -16,4 +16,4 @@
uint32_t ngx_murmur_hash2(u_char *data, size_t len);
-#endif /* _NGX_CRC_H_INCLUDED_ */
+#endif /* _NGX_MURMURHASH_H_INCLUDED_ */
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 9a98fccf233..c44ac96b8b7 100644
--- a/usr.sbin/nginx/src/core/ngx_open_file_cache.c
+++ b/usr.sbin/nginx/src/core/ngx_open_file_cache.c
@@ -22,8 +22,17 @@
static void ngx_open_file_cache_cleanup(void *data);
-static ngx_int_t ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of,
- ngx_log_t *log);
+#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);
+#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,
+ ngx_int_t access, ngx_log_t *log);
+static ngx_int_t ngx_file_info_wrapper(ngx_str_t *name,
+ ngx_open_file_info_t *of, ngx_file_info_t *fi, ngx_log_t *log);
+static ngx_int_t ngx_open_and_stat_file(ngx_str_t *name,
+ ngx_open_file_info_t *of, ngx_log_t *log);
static void ngx_open_file_add_event(ngx_open_file_cache_t *cache,
ngx_cached_open_file_t *file, ngx_open_file_info_t *of, ngx_log_t *log);
static void ngx_open_file_cleanup(void *data);
@@ -147,9 +156,9 @@ ngx_open_cached_file(ngx_open_file_cache_t *cache, ngx_str_t *name,
if (of->test_only) {
- if (ngx_file_info(name->data, &fi) == NGX_FILE_ERROR) {
- of->err = ngx_errno;
- of->failed = ngx_file_info_n;
+ if (ngx_file_info_wrapper(name, of, &fi, pool->log)
+ == NGX_FILE_ERROR)
+ {
return NGX_ERROR;
}
@@ -170,7 +179,7 @@ ngx_open_cached_file(ngx_open_file_cache_t *cache, ngx_str_t *name,
return NGX_ERROR;
}
- rc = ngx_open_and_stat_file(name->data, of, pool->log);
+ rc = ngx_open_and_stat_file(name, of, pool->log);
if (rc == NGX_OK && !of->is_dir) {
cln->handler = ngx_pool_cleanup_file;
@@ -205,7 +214,7 @@ ngx_open_cached_file(ngx_open_file_cache_t *cache, ngx_str_t *name,
/* file was not used often enough to keep open */
- rc = ngx_open_and_stat_file(name->data, of, pool->log);
+ rc = ngx_open_and_stat_file(name, of, pool->log);
if (rc != NGX_OK && (of->err == 0 || !of->errors)) {
goto failed;
@@ -217,7 +226,12 @@ ngx_open_cached_file(ngx_open_file_cache_t *cache, ngx_str_t *name,
if (file->use_event
|| (file->event == NULL
&& (of->uniq == 0 || of->uniq == file->uniq)
- && now - file->created < of->valid))
+ && now - file->created < of->valid
+#if (NGX_HAVE_OPENAT)
+ && of->disable_symlinks == file->disable_symlinks
+ && of->disable_symlinks_from == file->disable_symlinks_from
+#endif
+ ))
{
if (file->err == 0) {
@@ -239,7 +253,12 @@ ngx_open_cached_file(ngx_open_file_cache_t *cache, ngx_str_t *name,
} else {
of->err = file->err;
+#if (NGX_HAVE_OPENAT)
+ of->failed = file->disable_symlinks ? ngx_openat_file_n
+ : ngx_open_file_n;
+#else
of->failed = ngx_open_file_n;
+#endif
}
goto found;
@@ -263,7 +282,7 @@ ngx_open_cached_file(ngx_open_file_cache_t *cache, ngx_str_t *name,
of->fd = file->fd;
of->uniq = file->uniq;
- rc = ngx_open_and_stat_file(name->data, of, pool->log);
+ rc = ngx_open_and_stat_file(name, of, pool->log);
if (rc != NGX_OK && (of->err == 0 || !of->errors)) {
goto failed;
@@ -311,8 +330,7 @@ ngx_open_cached_file(ngx_open_file_cache_t *cache, ngx_str_t *name,
if (ngx_close_file(file->fd) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno,
- ngx_close_file_n " \"%s\" failed",
- name->data);
+ ngx_close_file_n " \"%V\" failed", name);
}
goto add_event;
@@ -329,7 +347,7 @@ ngx_open_cached_file(ngx_open_file_cache_t *cache, ngx_str_t *name,
/* not found */
- rc = ngx_open_and_stat_file(name->data, of, pool->log);
+ rc = ngx_open_and_stat_file(name, of, pool->log);
if (rc != NGX_OK && (of->err == 0 || !of->errors)) {
goto failed;
@@ -376,6 +394,10 @@ update:
file->fd = of->fd;
file->err = of->err;
+#if (NGX_HAVE_OPENAT)
+ file->disable_symlinks = of->disable_symlinks;
+ file->disable_symlinks_from = of->disable_symlinks_from;
+#endif
if (of->err == 0) {
file->uniq = of->uniq;
@@ -452,7 +474,7 @@ failed:
if (of->fd != NGX_INVALID_FILE) {
if (ngx_close_file(of->fd) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno,
- ngx_close_file_n " \"%s\" failed", name->data);
+ ngx_close_file_n " \"%V\" failed", name);
}
}
@@ -460,17 +482,306 @@ failed:
}
+#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)
+{
+ ngx_fd_t fd;
+ ngx_err_t err;
+ ngx_file_info_t fi, atfi;
+
+ /*
+ * To allow symlinks with the same owner, use openat() (followed
+ * by fstat()) and fstatat(AT_SYMLINK_NOFOLLOW), and then compare
+ * uids between fstat() and fstatat().
+ *
+ * As there is a race between openat() and fstatat() we don't
+ * know if openat() in fact opened symlink or not. Therefore,
+ * we have to compare uids even if fstatat() reports the opened
+ * component isn't a symlink (as we don't know whether it was
+ * symlink during openat() or not).
+ */
+
+ fd = ngx_openat_file(at_fd, name, mode, create, access);
+
+ if (fd == NGX_INVALID_FILE) {
+ return NGX_INVALID_FILE;
+ }
+
+ if (ngx_file_at_info(at_fd, name, &atfi, AT_SYMLINK_NOFOLLOW)
+ == NGX_FILE_ERROR)
+ {
+ err = ngx_errno;
+ goto failed;
+ }
+
+ if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
+ err = ngx_errno;
+ goto failed;
+ }
+
+ if (fi.st_uid != atfi.st_uid) {
+ err = NGX_ELOOP;
+ goto failed;
+ }
+
+ return fd;
+
+failed:
+
+ if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ ngx_close_file_n " \"%V\" failed", name);
+ }
+
+ ngx_set_errno(err);
+
+ return NGX_INVALID_FILE;
+}
+
+#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, ngx_int_t access, ngx_log_t *log)
+{
+ ngx_fd_t fd;
+
+#if !(NGX_HAVE_OPENAT)
+
+ fd = ngx_open_file(name->data, mode, create, access);
+
+ if (fd == NGX_INVALID_FILE) {
+ of->err = ngx_errno;
+ of->failed = ngx_open_file_n;
+ return NGX_INVALID_FILE;
+ }
+
+ return fd;
+
+#else
+
+ u_char *p, *cp, *end;
+ ngx_fd_t at_fd;
+ ngx_str_t at_name;
+
+ if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_OFF) {
+ fd = ngx_open_file(name->data, mode, create, access);
+
+ if (fd == NGX_INVALID_FILE) {
+ of->err = ngx_errno;
+ of->failed = ngx_open_file_n;
+ return NGX_INVALID_FILE;
+ }
+
+ return fd;
+ }
+
+ p = name->data;
+ end = p + name->len;
+
+ at_name = *name;
+
+ if (of->disable_symlinks_from) {
+
+ cp = p + of->disable_symlinks_from;
+
+ *cp = '\0';
+
+ at_fd = ngx_open_file(p, NGX_FILE_SEARCH|NGX_FILE_NONBLOCK,
+ NGX_FILE_OPEN, 0);
+
+ *cp = '/';
+
+ if (at_fd == NGX_INVALID_FILE) {
+ of->err = ngx_errno;
+ of->failed = ngx_open_file_n;
+ return NGX_INVALID_FILE;
+ }
+
+ at_name.len = of->disable_symlinks_from;
+ p = cp + 1;
+
+ } else if (*p == '/') {
+
+ at_fd = ngx_open_file("/",
+ NGX_FILE_SEARCH|NGX_FILE_NONBLOCK,
+ NGX_FILE_OPEN, 0);
+
+ if (at_fd == NGX_INVALID_FILE) {
+ of->err = ngx_errno;
+ of->failed = ngx_openat_file_n;
+ return NGX_INVALID_FILE;
+ }
+
+ at_name.len = 1;
+ p++;
+
+ } else {
+ at_fd = NGX_AT_FDCWD;
+ }
+
+ for ( ;; ) {
+ cp = ngx_strlchr(p, end, '/');
+ if (cp == NULL) {
+ break;
+ }
+
+ if (cp == p) {
+ p++;
+ continue;
+ }
+
+ *cp = '\0';
+
+ if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_NOTOWNER) {
+ fd = ngx_openat_file_owner(at_fd, p,
+ NGX_FILE_SEARCH|NGX_FILE_NONBLOCK,
+ NGX_FILE_OPEN, 0, log);
+
+ } else {
+ fd = ngx_openat_file(at_fd, p,
+ NGX_FILE_SEARCH|NGX_FILE_NONBLOCK|NGX_FILE_NOFOLLOW,
+ NGX_FILE_OPEN, 0);
+ }
+
+ *cp = '/';
+
+ if (fd == NGX_INVALID_FILE) {
+ of->err = ngx_errno;
+ of->failed = ngx_openat_file_n;
+ goto failed;
+ }
+
+ if (at_fd != NGX_AT_FDCWD && ngx_close_file(at_fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ ngx_close_file_n " \"%V\" failed", &at_name);
+ }
+
+ p = cp + 1;
+ at_fd = fd;
+ at_name.len = cp - at_name.data;
+ }
+
+ if (p == end) {
+
+ /*
+ * If pathname ends with a trailing slash, assume the last path
+ * component is a directory and reopen it with requested flags;
+ * if not, fail with ENOTDIR as per POSIX.
+ *
+ * We cannot rely on O_DIRECTORY in the loop above to check
+ * that the last path component is a directory because
+ * O_DIRECTORY doesn't work on FreeBSD 8. Fortunately, by
+ * reopening a directory, we don't depend on it at all.
+ */
+
+ fd = ngx_openat_file(at_fd, ".", mode, create, access);
+ goto done;
+ }
+
+ if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_NOTOWNER
+ && !(create & (NGX_FILE_CREATE_OR_OPEN|NGX_FILE_TRUNCATE)))
+ {
+ fd = ngx_openat_file_owner(at_fd, p, mode, create, access, log);
+
+ } else {
+ fd = ngx_openat_file(at_fd, p, mode|NGX_FILE_NOFOLLOW, create, access);
+ }
+
+done:
+
+ if (fd == NGX_INVALID_FILE) {
+ of->err = ngx_errno;
+ of->failed = ngx_openat_file_n;
+ }
+
+failed:
+
+ if (at_fd != NGX_AT_FDCWD && ngx_close_file(at_fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ ngx_close_file_n " \"%V\" failed", &at_name);
+ }
+
+ return fd;
+#endif
+}
+
+
static ngx_int_t
-ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of, ngx_log_t *log)
+ngx_file_info_wrapper(ngx_str_t *name, ngx_open_file_info_t *of,
+ ngx_file_info_t *fi, ngx_log_t *log)
+{
+ ngx_int_t rc;
+
+#if !(NGX_HAVE_OPENAT)
+
+ rc = ngx_file_info(name->data, fi);
+
+ if (rc == NGX_FILE_ERROR) {
+ of->err = ngx_errno;
+ of->failed = ngx_file_info_n;
+ return NGX_FILE_ERROR;
+ }
+
+ return rc;
+
+#else
+
+ ngx_fd_t fd;
+
+ if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_OFF) {
+
+ rc = ngx_file_info(name->data, fi);
+
+ if (rc == NGX_FILE_ERROR) {
+ of->err = ngx_errno;
+ of->failed = ngx_file_info_n;
+ return NGX_FILE_ERROR;
+ }
+
+ return rc;
+ }
+
+ fd = ngx_open_file_wrapper(name, of, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK,
+ NGX_FILE_OPEN, 0, log);
+
+ if (fd == NGX_INVALID_FILE) {
+ return NGX_FILE_ERROR;
+ }
+
+ rc = ngx_fd_info(fd, fi);
+
+ if (rc == NGX_FILE_ERROR) {
+ of->err = ngx_errno;
+ of->failed = ngx_fd_info_n;
+ }
+
+ if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ ngx_close_file_n " \"%V\" failed", name);
+ }
+
+ return rc;
+#endif
+}
+
+
+static ngx_int_t
+ngx_open_and_stat_file(ngx_str_t *name, ngx_open_file_info_t *of,
+ ngx_log_t *log)
{
ngx_fd_t fd;
ngx_file_info_t fi;
if (of->fd != NGX_INVALID_FILE) {
- if (ngx_file_info(name, &fi) == NGX_FILE_ERROR) {
- of->failed = ngx_file_info_n;
- goto failed;
+ if (ngx_file_info_wrapper(name, of, &fi, log) == NGX_FILE_ERROR) {
+ of->fd = NGX_INVALID_FILE;
+ return NGX_ERROR;
}
if (of->uniq == ngx_file_uniq(&fi)) {
@@ -479,9 +790,9 @@ ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of, ngx_log_t *log)
} else if (of->test_dir) {
- if (ngx_file_info(name, &fi) == NGX_FILE_ERROR) {
- of->failed = ngx_file_info_n;
- goto failed;
+ if (ngx_file_info_wrapper(name, of, &fi, log) == NGX_FILE_ERROR) {
+ of->fd = NGX_INVALID_FILE;
+ return NGX_ERROR;
}
if (ngx_is_dir(&fi)) {
@@ -496,26 +807,27 @@ ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of, ngx_log_t *log)
* This flag has no effect on a regular files.
*/
- fd = ngx_open_file(name, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK,
- NGX_FILE_OPEN, 0);
+ fd = ngx_open_file_wrapper(name, of, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK,
+ NGX_FILE_OPEN, 0, log);
} else {
- fd = ngx_open_file(name, NGX_FILE_APPEND, NGX_FILE_CREATE_OR_OPEN,
- NGX_FILE_DEFAULT_ACCESS);
+ fd = ngx_open_file_wrapper(name, of, NGX_FILE_APPEND,
+ NGX_FILE_CREATE_OR_OPEN,
+ NGX_FILE_DEFAULT_ACCESS, log);
}
if (fd == NGX_INVALID_FILE) {
- of->failed = ngx_open_file_n;
- goto failed;
+ of->fd = NGX_INVALID_FILE;
+ return NGX_ERROR;
}
if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
- ngx_fd_info_n " \"%s\" failed", name);
+ ngx_fd_info_n " \"%V\" failed", name);
if (ngx_close_file(fd) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
- ngx_close_file_n " \"%s\" failed", name);
+ ngx_close_file_n " \"%V\" failed", name);
}
of->fd = NGX_INVALID_FILE;
@@ -526,7 +838,7 @@ ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of, ngx_log_t *log)
if (ngx_is_dir(&fi)) {
if (ngx_close_file(fd) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
- ngx_close_file_n " \"%s\" failed", name);
+ ngx_close_file_n " \"%V\" failed", name);
}
of->fd = NGX_INVALID_FILE;
@@ -537,14 +849,14 @@ ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of, ngx_log_t *log)
if (of->read_ahead && ngx_file_size(&fi) > NGX_MIN_READ_AHEAD) {
if (ngx_read_ahead(fd, of->read_ahead) == NGX_ERROR) {
ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
- ngx_read_ahead_n " \"%s\" failed", name);
+ ngx_read_ahead_n " \"%V\" failed", name);
}
}
if (of->directio <= ngx_file_size(&fi)) {
if (ngx_directio_on(fd) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
- ngx_directio_on_n " \"%s\" failed", name);
+ ngx_directio_on_n " \"%V\" failed", name);
} else {
of->is_directio = 1;
@@ -564,13 +876,6 @@ done:
of->is_exec = ngx_is_exec(&fi);
return NGX_OK;
-
-failed:
-
- of->fd = NGX_INVALID_FILE;
- of->err = ngx_errno;
-
- return NGX_ERROR;
}
diff --git a/usr.sbin/nginx/src/core/ngx_open_file_cache.h b/usr.sbin/nginx/src/core/ngx_open_file_cache.h
index 436de30609d..d119c1296f4 100644
--- a/usr.sbin/nginx/src/core/ngx_open_file_cache.h
+++ b/usr.sbin/nginx/src/core/ngx_open_file_cache.h
@@ -32,6 +32,11 @@ typedef struct {
ngx_uint_t min_uses;
+#if (NGX_HAVE_OPENAT)
+ size_t disable_symlinks_from;
+ unsigned disable_symlinks:2;
+#endif
+
unsigned test_dir:1;
unsigned test_only:1;
unsigned log:1;
@@ -64,6 +69,11 @@ struct ngx_cached_open_file_s {
uint32_t uses;
+#if (NGX_HAVE_OPENAT)
+ size_t disable_symlinks_from;
+ unsigned disable_symlinks:2;
+#endif
+
unsigned count:24;
unsigned close:1;
unsigned use_event:1;
diff --git a/usr.sbin/nginx/src/core/ngx_output_chain.c b/usr.sbin/nginx/src/core/ngx_output_chain.c
index 64500d52886..3cb60ea73dd 100644
--- a/usr.sbin/nginx/src/core/ngx_output_chain.c
+++ b/usr.sbin/nginx/src/core/ngx_output_chain.c
@@ -209,7 +209,8 @@ ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in)
return last;
}
- ngx_chain_update_chains(&ctx->free, &ctx->busy, &out, ctx->tag);
+ ngx_chain_update_chains(ctx->pool, &ctx->free, &ctx->busy, &out,
+ ctx->tag);
last_out = &out;
}
}
diff --git a/usr.sbin/nginx/src/core/ngx_parse.h b/usr.sbin/nginx/src/core/ngx_parse.h
index 0c8114fb693..ec093b5a2be 100644
--- a/usr.sbin/nginx/src/core/ngx_parse.h
+++ b/usr.sbin/nginx/src/core/ngx_parse.h
@@ -13,9 +13,6 @@
#include <ngx_core.h>
-#define NGX_PARSE_LARGE_TIME -2
-
-
ssize_t ngx_parse_size(ngx_str_t *line);
off_t ngx_parse_offset(ngx_str_t *line);
ngx_int_t ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec);
diff --git a/usr.sbin/nginx/src/core/ngx_rbtree.c b/usr.sbin/nginx/src/core/ngx_rbtree.c
index 6ae4d5c05ab..914ca7e884b 100644
--- a/usr.sbin/nginx/src/core/ngx_rbtree.c
+++ b/usr.sbin/nginx/src/core/ngx_rbtree.c
@@ -136,8 +136,7 @@ ngx_rbtree_insert_timer_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node,
/* node->key < temp->key */
- p = ((ngx_rbtree_key_int_t) node->key - (ngx_rbtree_key_int_t) temp->key
- < 0)
+ p = ((ngx_rbtree_key_int_t) (node->key - temp->key) < 0)
? &temp->left : &temp->right;
if (*p == sentinel) {
diff --git a/usr.sbin/nginx/src/core/ngx_regex.c b/usr.sbin/nginx/src/core/ngx_regex.c
index 979110e75cc..677f862bf17 100644
--- a/usr.sbin/nginx/src/core/ngx_regex.c
+++ b/usr.sbin/nginx/src/core/ngx_regex.c
@@ -9,11 +9,64 @@
#include <ngx_core.h>
+typedef struct {
+ ngx_flag_t pcre_jit;
+} ngx_regex_conf_t;
+
+
static void * ngx_libc_cdecl ngx_regex_malloc(size_t size);
static void ngx_libc_cdecl ngx_regex_free(void *p);
+#if (NGX_HAVE_PCRE_JIT)
+static void ngx_pcre_free_studies(void *data);
+#endif
+
+static ngx_int_t ngx_regex_module_init(ngx_cycle_t *cycle);
+
+static void *ngx_regex_create_conf(ngx_cycle_t *cycle);
+static char *ngx_regex_init_conf(ngx_cycle_t *cycle, void *conf);
+
+static char *ngx_regex_pcre_jit(ngx_conf_t *cf, void *post, void *data);
+static ngx_conf_post_t ngx_regex_pcre_jit_post = { ngx_regex_pcre_jit };
+
+
+static ngx_command_t ngx_regex_commands[] = {
+
+ { ngx_string("pcre_jit"),
+ NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_flag_slot,
+ 0,
+ offsetof(ngx_regex_conf_t, pcre_jit),
+ &ngx_regex_pcre_jit_post },
+
+ ngx_null_command
+};
+
+
+static ngx_core_module_t ngx_regex_module_ctx = {
+ ngx_string("regex"),
+ ngx_regex_create_conf,
+ ngx_regex_init_conf
+};
+
+
+ngx_module_t ngx_regex_module = {
+ NGX_MODULE_V1,
+ &ngx_regex_module_ctx, /* module context */
+ ngx_regex_commands, /* module directives */
+ NGX_CORE_MODULE, /* module type */
+ NULL, /* init master */
+ ngx_regex_module_init, /* init module */
+ NULL, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ NULL, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
static ngx_pool_t *ngx_pcre_pool;
+static ngx_list_t *ngx_pcre_studies;
void
@@ -63,10 +116,11 @@ ngx_regex_malloc_done(void)
ngx_int_t
ngx_regex_compile(ngx_regex_compile_t *rc)
{
- int n, erroff;
- char *p;
- const char *errstr;
- ngx_regex_t *re;
+ int n, erroff;
+ char *p;
+ pcre *re;
+ const char *errstr;
+ ngx_regex_elt_t *elt;
ngx_regex_malloc_init(rc->pool);
@@ -93,7 +147,24 @@ ngx_regex_compile(ngx_regex_compile_t *rc)
return NGX_ERROR;
}
- rc->regex = re;
+ rc->regex = ngx_pcalloc(rc->pool, sizeof(ngx_regex_t));
+ if (rc->regex == NULL) {
+ return NGX_ERROR;
+ }
+
+ rc->regex->pcre = re;
+
+ /* do not study at runtime */
+
+ if (ngx_pcre_studies != NULL) {
+ elt = ngx_list_push(ngx_pcre_studies);
+ if (elt == NULL) {
+ return NGX_ERROR;
+ }
+
+ elt->regex = rc->regex;
+ elt->name = rc->pattern.data;
+ }
n = pcre_fullinfo(re, NULL, PCRE_INFO_CAPTURECOUNT, &rc->captures);
if (n < 0) {
@@ -204,3 +275,190 @@ ngx_regex_free(void *p)
{
return;
}
+
+
+#if (NGX_HAVE_PCRE_JIT)
+
+static void
+ngx_pcre_free_studies(void *data)
+{
+ ngx_list_t *studies = data;
+
+ ngx_uint_t i;
+ ngx_list_part_t *part;
+ ngx_regex_elt_t *elts;
+
+ part = &studies->part;
+ elts = part->elts;
+
+ for (i = 0 ; /* void */ ; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+
+ part = part->next;
+ elts = part->elts;
+ i = 0;
+ }
+
+ if (elts[i].regex->extra != NULL) {
+ pcre_free_study(elts[i].regex->extra);
+ }
+ }
+}
+
+#endif
+
+
+static ngx_int_t
+ngx_regex_module_init(ngx_cycle_t *cycle)
+{
+ int opt;
+ const char *errstr;
+ ngx_uint_t i;
+ ngx_list_part_t *part;
+ ngx_regex_elt_t *elts;
+
+ opt = 0;
+
+#if (NGX_HAVE_PCRE_JIT)
+ {
+ ngx_regex_conf_t *rcf;
+ ngx_pool_cleanup_t *cln;
+
+ rcf = (ngx_regex_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_regex_module);
+
+ if (rcf->pcre_jit) {
+ opt = PCRE_STUDY_JIT_COMPILE;
+
+ /*
+ * The PCRE JIT compiler uses mmap for its executable codes, so we
+ * have to explicitly call the pcre_free_study() function to free
+ * this memory.
+ */
+
+ cln = ngx_pool_cleanup_add(cycle->pool, 0);
+ if (cln == NULL) {
+ return NGX_ERROR;
+ }
+
+ cln->handler = ngx_pcre_free_studies;
+ cln->data = ngx_pcre_studies;
+ }
+ }
+#endif
+
+ ngx_regex_malloc_init(cycle->pool);
+
+ part = &ngx_pcre_studies->part;
+ elts = part->elts;
+
+ for (i = 0 ; /* void */ ; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+
+ part = part->next;
+ elts = part->elts;
+ i = 0;
+ }
+
+ elts[i].regex->extra = pcre_study(elts[i].regex->pcre, opt, &errstr);
+
+ if (errstr != NULL) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "pcre_study() failed: %s in \"%s\"",
+ errstr, elts[i].name);
+ }
+
+#if (NGX_HAVE_PCRE_JIT)
+ if (opt & PCRE_STUDY_JIT_COMPILE) {
+ int jit, n;
+
+ jit = 0;
+ n = pcre_fullinfo(elts[i].regex->pcre, elts[i].regex->extra,
+ PCRE_INFO_JIT, &jit);
+
+ if (n != 0 || jit != 1) {
+ ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
+ "JIT compiler does not support pattern: \"%s\"",
+ elts[i].name);
+ }
+ }
+#endif
+ }
+
+ ngx_regex_malloc_done();
+
+ ngx_pcre_studies = NULL;
+
+ return NGX_OK;
+}
+
+
+static void *
+ngx_regex_create_conf(ngx_cycle_t *cycle)
+{
+ ngx_regex_conf_t *rcf;
+
+ rcf = ngx_pcalloc(cycle->pool, sizeof(ngx_regex_conf_t));
+ if (rcf == NULL) {
+ return NULL;
+ }
+
+ rcf->pcre_jit = NGX_CONF_UNSET;
+
+ ngx_pcre_studies = ngx_list_create(cycle->pool, 8, sizeof(ngx_regex_elt_t));
+ if (ngx_pcre_studies == NULL) {
+ return NULL;
+ }
+
+ return rcf;
+}
+
+
+static char *
+ngx_regex_init_conf(ngx_cycle_t *cycle, void *conf)
+{
+ ngx_regex_conf_t *rcf = conf;
+
+ ngx_conf_init_value(rcf->pcre_jit, 0);
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_regex_pcre_jit(ngx_conf_t *cf, void *post, void *data)
+{
+ ngx_flag_t *fp = data;
+
+ if (*fp == 0) {
+ return NGX_CONF_OK;
+ }
+
+#if (NGX_HAVE_PCRE_JIT)
+ {
+ int jit, r;
+
+ jit = 0;
+ r = pcre_config(PCRE_CONFIG_JIT, &jit);
+
+ if (r != 0 || jit != 1) {
+ ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+ "PCRE library does not support JIT");
+ *fp = 0;
+ }
+ }
+#else
+ ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+ "nginx was built without PCRE JIT support");
+ *fp = 0;
+#endif
+
+ return NGX_CONF_OK;
+}
diff --git a/usr.sbin/nginx/src/core/ngx_regex.h b/usr.sbin/nginx/src/core/ngx_regex.h
index 58b9eef7621..55bd331bb69 100644
--- a/usr.sbin/nginx/src/core/ngx_regex.h
+++ b/usr.sbin/nginx/src/core/ngx_regex.h
@@ -19,7 +19,11 @@
#define NGX_REGEX_CASELESS PCRE_CASELESS
-typedef pcre ngx_regex_t;
+
+typedef struct {
+ pcre *pcre;
+ pcre_extra *extra;
+} ngx_regex_t;
typedef struct {
@@ -46,7 +50,7 @@ void ngx_regex_init(void);
ngx_int_t ngx_regex_compile(ngx_regex_compile_t *rc);
#define ngx_regex_exec(re, s, captures, size) \
- pcre_exec(re, NULL, (const char *) (s)->data, (s)->len, 0, 0, \
+ pcre_exec(re->pcre, re->extra, (const char *) (s)->data, (s)->len, 0, 0, \
captures, size)
#define ngx_regex_exec_n "pcre_exec()"
diff --git a/usr.sbin/nginx/src/core/ngx_resolver.c b/usr.sbin/nginx/src/core/ngx_resolver.c
index 817e65df101..02c484da694 100644
--- a/usr.sbin/nginx/src/core/ngx_resolver.c
+++ b/usr.sbin/nginx/src/core/ngx_resolver.c
@@ -92,8 +92,11 @@ static u_char *ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len);
ngx_resolver_t *
-ngx_resolver_create(ngx_conf_t *cf, ngx_addr_t *addr)
+ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n)
{
+ ngx_str_t s;
+ ngx_url_t u;
+ ngx_uint_t i;
ngx_resolver_t *r;
ngx_pool_cleanup_t *cln;
ngx_udp_connection_t *uc;
@@ -110,6 +113,15 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_addr_t *addr)
return NULL;
}
+ if (n) {
+ if (ngx_array_init(&r->udp_connections, cf->pool, n,
+ sizeof(ngx_udp_connection_t))
+ != NGX_OK)
+ {
+ return NULL;
+ }
+ }
+
cln->data = r;
r->event = ngx_calloc(sizeof(ngx_event_t), cf->log);
@@ -136,22 +148,47 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_addr_t *addr)
r->resend_timeout = 5;
r->expire = 30;
- r->valid = 300;
+ r->valid = 0;
r->log = &cf->cycle->new_log;
r->log_level = NGX_LOG_ERR;
- if (addr) {
- uc = ngx_calloc(sizeof(ngx_udp_connection_t), cf->log);
+ for (i = 0; i < n; i++) {
+ if (ngx_strncmp(names[i].data, "valid=", 6) == 0) {
+ s.len = names[i].len - 6;
+ s.data = names[i].data + 6;
+
+ r->valid = ngx_parse_time(&s, 1);
+
+ if (r->valid == (time_t) NGX_ERROR) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid parameter: %V", &names[i]);
+ return NULL;
+ }
+
+ continue;
+ }
+
+ ngx_memzero(&u, sizeof(ngx_url_t));
+
+ u.host = names[i];
+ u.port = 53;
+
+ if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V: %s", &u.host, u.err);
+ return NULL;
+ }
+
+ uc = ngx_array_push(&r->udp_connections);
if (uc == NULL) {
return NULL;
}
- r->udp_connection = uc;
+ ngx_memzero(uc, sizeof(ngx_udp_connection_t));
- uc->sockaddr = addr->sockaddr;
- uc->socklen = addr->socklen;
- uc->server = addr->name;
+ uc->sockaddr = u.addrs->sockaddr;
+ uc->socklen = u.addrs->socklen;
+ uc->server = u.addrs->name;
}
return r;
@@ -163,6 +200,9 @@ ngx_resolver_cleanup(void *data)
{
ngx_resolver_t *r = data;
+ ngx_uint_t i;
+ ngx_udp_connection_t *uc;
+
if (r) {
ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
"cleanup resolver");
@@ -175,12 +215,13 @@ ngx_resolver_cleanup(void *data)
ngx_free(r->event);
}
- if (r->udp_connection) {
- if (r->udp_connection->connection) {
- ngx_close_connection(r->udp_connection->connection);
- }
- ngx_free(r->udp_connection);
+ uc = r->udp_connections.elts;
+
+ for (i = 0; i < r->udp_connections.nelts; i++) {
+ if (uc[i].connection) {
+ ngx_close_connection(uc[i].connection);
+ }
}
ngx_free(r);
@@ -238,7 +279,7 @@ ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp)
}
}
- if (r->udp_connection == NULL) {
+ if (r->udp_connections.nelts == 0) {
return NGX_NO_RESOLVER;
}
@@ -822,7 +863,12 @@ ngx_resolver_send_query(ngx_resolver_t *r, ngx_resolver_node_t *rn)
ssize_t n;
ngx_udp_connection_t *uc;
- uc = r->udp_connection;
+ uc = r->udp_connections.elts;
+
+ uc = &uc[r->last_connection++];
+ if (r->last_connection == r->udp_connections.nelts) {
+ r->last_connection = 0;
+ }
if (uc->connection == NULL) {
@@ -1121,6 +1167,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
char *err;
u_char *cname;
size_t len;
+ int32_t ttl;
uint32_t hash;
in_addr_t addr, *addrs;
ngx_str_t name;
@@ -1191,6 +1238,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
addrs = NULL;
cname = NULL;
qtype = 0;
+ ttl = 0;
for (a = 0; a < nan; a++) {
@@ -1230,6 +1278,12 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
qtype = (an->type_hi << 8) + an->type_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 (ttl < 0) {
+ ttl = 0;
+ }
if (qtype == NGX_RESOLVE_A) {
@@ -1259,8 +1313,9 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
}
}
- ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
- "resolver naddrs:%ui cname:%p", naddrs, cname);
+ ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
+ "resolver naddrs:%ui cname:%p ttl:%d",
+ naddrs, cname, ttl);
if (naddrs) {
@@ -1329,7 +1384,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
ngx_queue_remove(&rn->queue);
- rn->valid = ngx_time() + r->valid;
+ rn->valid = ngx_time() + (r->valid ? r->valid : ttl);
rn->expire = ngx_time() + r->expire;
ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
@@ -1371,7 +1426,8 @@ 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;
+
+ rn->valid = ngx_time() + (r->valid ? r->valid : ttl);
rn->expire = ngx_time() + r->expire;
ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
@@ -1422,6 +1478,7 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
char *err;
size_t len;
in_addr_t addr;
+ int32_t ttl;
ngx_int_t digit;
ngx_str_t name;
ngx_uint_t i, mask, qident;
@@ -1517,6 +1574,12 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
an = (ngx_resolver_an_t *) &buf[i + 2];
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 (ttl < 0) {
+ ttl = 0;
+ }
ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
"resolver qt:%ui cl:%ui len:%uz",
@@ -1553,7 +1616,7 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
ngx_queue_remove(&rn->queue);
- rn->valid = ngx_time() + r->valid;
+ 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);
@@ -1777,7 +1840,7 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
len++;
} else {
- if (len == 0) {
+ if (len == 0 || len > 255) {
return NGX_DECLINED;
}
@@ -1788,6 +1851,10 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
p--;
}
+ if (len == 0 || len > 255) {
+ return NGX_DECLINED;
+ }
+
*p = (u_char) len;
return NGX_OK;
diff --git a/usr.sbin/nginx/src/core/ngx_resolver.h b/usr.sbin/nginx/src/core/ngx_resolver.h
index 2301623df94..ae34ca56d3a 100644
--- a/usr.sbin/nginx/src/core/ngx_resolver.h
+++ b/usr.sbin/nginx/src/core/ngx_resolver.h
@@ -78,16 +78,16 @@ typedef struct {
typedef struct {
/* has to be pointer because of "incomplete type" */
ngx_event_t *event;
-
- /* TODO: DNS peers balancer */
- /* STUB */
- ngx_udp_connection_t *udp_connection;
-
+ void *dummy;
ngx_log_t *log;
/* ident must be after 3 pointers */
ngx_int_t ident;
+ /* simple round robin DNS peers balancer */
+ ngx_array_t udp_connections;
+ ngx_uint_t last_connection;
+
ngx_rbtree_t name_rbtree;
ngx_rbtree_node_t name_sentinel;
@@ -124,8 +124,6 @@ struct ngx_resolver_ctx_s {
in_addr_t *addrs;
in_addr_t addr;
- /* TODO: DNS peers balancer ctx */
-
ngx_resolver_handler_pt handler;
void *data;
ngx_msec_t timeout;
@@ -136,7 +134,8 @@ struct ngx_resolver_ctx_s {
};
-ngx_resolver_t *ngx_resolver_create(ngx_conf_t *cf, ngx_addr_t *addr);
+ngx_resolver_t *ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names,
+ ngx_uint_t n);
ngx_resolver_ctx_t *ngx_resolve_start(ngx_resolver_t *r,
ngx_resolver_ctx_t *temp);
ngx_int_t ngx_resolve_name(ngx_resolver_ctx_t *ctx);
diff --git a/usr.sbin/nginx/src/core/ngx_shmtx.c b/usr.sbin/nginx/src/core/ngx_shmtx.c
index 368456e14f8..085294a914a 100644
--- a/usr.sbin/nginx/src/core/ngx_shmtx.c
+++ b/usr.sbin/nginx/src/core/ngx_shmtx.c
@@ -12,10 +12,13 @@
#if (NGX_HAVE_ATOMIC_OPS)
+static void ngx_shmtx_wakeup(ngx_shmtx_t *mtx);
+
+
ngx_int_t
-ngx_shmtx_create(ngx_shmtx_t *mtx, void *addr, u_char *name)
+ngx_shmtx_create(ngx_shmtx_t *mtx, ngx_shmtx_sh_t *addr, u_char *name)
{
- mtx->lock = addr;
+ mtx->lock = &addr->lock;
if (mtx->spin == (ngx_uint_t) -1) {
return NGX_OK;
@@ -25,6 +28,8 @@ ngx_shmtx_create(ngx_shmtx_t *mtx, void *addr, u_char *name)
#if (NGX_HAVE_POSIX_SEM)
+ mtx->wait = &addr->wait;
+
if (sem_init(&mtx->sem, 1, 0) == -1) {
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
"sem_init() failed");
@@ -57,12 +62,7 @@ ngx_shmtx_destory(ngx_shmtx_t *mtx)
ngx_uint_t
ngx_shmtx_trylock(ngx_shmtx_t *mtx)
{
- ngx_atomic_uint_t val;
-
- val = *mtx->lock;
-
- return ((val & 0x80000000) == 0
- && ngx_atomic_cmp_set(mtx->lock, val, val | 0x80000000));
+ return (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid));
}
@@ -70,17 +70,12 @@ void
ngx_shmtx_lock(ngx_shmtx_t *mtx)
{
ngx_uint_t i, n;
- ngx_atomic_uint_t val;
ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "shmtx lock");
for ( ;; ) {
- val = *mtx->lock;
-
- if ((val & 0x80000000) == 0
- && ngx_atomic_cmp_set(mtx->lock, val, val | 0x80000000))
- {
+ if (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid)) {
return;
}
@@ -92,10 +87,8 @@ ngx_shmtx_lock(ngx_shmtx_t *mtx)
ngx_cpu_pause();
}
- val = *mtx->lock;
-
- if ((val & 0x80000000) == 0
- && ngx_atomic_cmp_set(mtx->lock, val, val | 0x80000000))
+ if (*mtx->lock == 0
+ && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid))
{
return;
}
@@ -105,24 +98,24 @@ ngx_shmtx_lock(ngx_shmtx_t *mtx)
#if (NGX_HAVE_POSIX_SEM)
if (mtx->semaphore) {
- val = *mtx->lock;
+ (void) ngx_atomic_fetch_add(mtx->wait, 1);
- if ((val & 0x80000000)
- && ngx_atomic_cmp_set(mtx->lock, val, val + 1))
- {
- ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
- "shmtx wait %XA", val);
+ if (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid)) {
+ return;
+ }
- while (sem_wait(&mtx->sem) == -1) {
- ngx_err_t err;
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
+ "shmtx wait %uA", *mtx->wait);
- err = ngx_errno;
+ while (sem_wait(&mtx->sem) == -1) {
+ ngx_err_t err;
- if (err != NGX_EINTR) {
- ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err,
- "sem_wait() failed while waiting on shmtx");
- break;
- }
+ err = ngx_errno;
+
+ if (err != NGX_EINTR) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err,
+ "sem_wait() failed while waiting on shmtx");
+ break;
}
ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
@@ -142,31 +135,56 @@ ngx_shmtx_lock(ngx_shmtx_t *mtx)
void
ngx_shmtx_unlock(ngx_shmtx_t *mtx)
{
- ngx_atomic_uint_t val, old, wait;
-
if (mtx->spin != (ngx_uint_t) -1) {
ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "shmtx unlock");
}
- for ( ;; ) {
+ if (ngx_atomic_cmp_set(mtx->lock, ngx_pid, 0)) {
+ ngx_shmtx_wakeup(mtx);
+ }
+}
- old = *mtx->lock;
- wait = old & 0x7fffffff;
- val = wait ? wait - 1 : 0;
- if (ngx_atomic_cmp_set(mtx->lock, old, val)) {
- break;
- }
+ngx_uint_t
+ngx_shmtx_force_unlock(ngx_shmtx_t *mtx, ngx_pid_t pid)
+{
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
+ "shmtx forced unlock");
+
+ if (ngx_atomic_cmp_set(mtx->lock, pid, 0)) {
+ ngx_shmtx_wakeup(mtx);
+ return 1;
}
+ return 0;
+}
+
+
+static void
+ngx_shmtx_wakeup(ngx_shmtx_t *mtx)
+{
#if (NGX_HAVE_POSIX_SEM)
+ ngx_atomic_uint_t wait;
- if (wait == 0 || !mtx->semaphore) {
+ if (!mtx->semaphore) {
return;
}
+ for ( ;; ) {
+
+ wait = *mtx->wait;
+
+ if (wait == 0) {
+ return;
+ }
+
+ if (ngx_atomic_cmp_set(mtx->wait, wait, wait - 1)) {
+ break;
+ }
+ }
+
ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
- "shmtx wake %XA", old);
+ "shmtx wake %uA", wait);
if (sem_post(&mtx->sem) == -1) {
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
@@ -181,7 +199,7 @@ ngx_shmtx_unlock(ngx_shmtx_t *mtx)
ngx_int_t
-ngx_shmtx_create(ngx_shmtx_t *mtx, void *addr, u_char *name)
+ngx_shmtx_create(ngx_shmtx_t *mtx, ngx_shmtx_sh_t *addr, u_char *name)
{
if (mtx->name) {
@@ -281,4 +299,11 @@ ngx_shmtx_unlock(ngx_shmtx_t *mtx)
ngx_log_abort(err, ngx_unlock_fd_n " %s failed", mtx->name);
}
+
+ngx_uint_t
+ngx_shmtx_force_unlock(ngx_shmtx_t *mtx, ngx_pid_t pid)
+{
+ return 0;
+}
+
#endif
diff --git a/usr.sbin/nginx/src/core/ngx_shmtx.h b/usr.sbin/nginx/src/core/ngx_shmtx.h
index 70a44cbc5fb..830b6f5b198 100644
--- a/usr.sbin/nginx/src/core/ngx_shmtx.h
+++ b/usr.sbin/nginx/src/core/ngx_shmtx.h
@@ -14,9 +14,18 @@
typedef struct {
+ ngx_atomic_t lock;
+#if (NGX_HAVE_POSIX_SEM)
+ ngx_atomic_t wait;
+#endif
+} ngx_shmtx_sh_t;
+
+
+typedef struct {
#if (NGX_HAVE_ATOMIC_OPS)
ngx_atomic_t *lock;
#if (NGX_HAVE_POSIX_SEM)
+ ngx_atomic_t *wait;
ngx_uint_t semaphore;
sem_t sem;
#endif
@@ -28,11 +37,13 @@ typedef struct {
} ngx_shmtx_t;
-ngx_int_t ngx_shmtx_create(ngx_shmtx_t *mtx, void *addr, u_char *name);
+ngx_int_t ngx_shmtx_create(ngx_shmtx_t *mtx, ngx_shmtx_sh_t *addr,
+ u_char *name);
void ngx_shmtx_destory(ngx_shmtx_t *mtx);
ngx_uint_t ngx_shmtx_trylock(ngx_shmtx_t *mtx);
void ngx_shmtx_lock(ngx_shmtx_t *mtx);
void ngx_shmtx_unlock(ngx_shmtx_t *mtx);
+ngx_uint_t ngx_shmtx_force_unlock(ngx_shmtx_t *mtx, ngx_pid_t pid);
#endif /* _NGX_SHMTX_H_INCLUDED_ */
diff --git a/usr.sbin/nginx/src/core/ngx_slab.c b/usr.sbin/nginx/src/core/ngx_slab.c
index 74f23a35e19..3d566037708 100644
--- a/usr.sbin/nginx/src/core/ngx_slab.c
+++ b/usr.sbin/nginx/src/core/ngx_slab.c
@@ -43,14 +43,14 @@
#if (NGX_DEBUG_MALLOC)
-#define ngx_slab_junk(p, size) ngx_memset(p, 0xD0, size)
+#define ngx_slab_junk(p, size) ngx_memset(p, 0xA5, size)
#else
-#if (NGX_FREEBSD)
+#if (NGX_HAVE_DEBUG_MALLOC)
#define ngx_slab_junk(p, size) \
- if (ngx_freebsd_debug_malloc) ngx_memset(p, 0xD0, size)
+ if (ngx_debug_malloc) ngx_memset(p, 0xA5, size)
#else
diff --git a/usr.sbin/nginx/src/core/ngx_slab.h b/usr.sbin/nginx/src/core/ngx_slab.h
index efb5d01f3b3..c5e420bfa8e 100644
--- a/usr.sbin/nginx/src/core/ngx_slab.h
+++ b/usr.sbin/nginx/src/core/ngx_slab.h
@@ -23,7 +23,7 @@ struct ngx_slab_page_s {
typedef struct {
- ngx_atomic_t lock;
+ ngx_shmtx_sh_t lock;
size_t min_size;
size_t min_shift;
diff --git a/usr.sbin/nginx/src/core/ngx_string.c b/usr.sbin/nginx/src/core/ngx_string.c
index 05184479c96..53cb946fee0 100644
--- a/usr.sbin/nginx/src/core/ngx_string.c
+++ b/usr.sbin/nginx/src/core/ngx_string.c
@@ -146,12 +146,12 @@ ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args)
{
u_char *p, zero;
int d;
- double f, scale;
+ double f;
size_t len, slen;
int64_t i64;
- uint64_t ui64;
+ uint64_t ui64, frac;
ngx_msec_t ms;
- ngx_uint_t width, sign, hex, max_width, frac_width, n;
+ ngx_uint_t width, sign, hex, max_width, frac_width, scale, n;
ngx_str_t *v;
ngx_variable_value_t *vv;
@@ -365,28 +365,31 @@ ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args)
}
ui64 = (int64_t) f;
-
- buf = ngx_sprintf_num(buf, last, ui64, zero, 0, width);
+ frac = 0;
if (frac_width) {
- if (buf < last) {
- *buf++ = '.';
+ scale = 1;
+ for (n = frac_width; n; n--) {
+ scale *= 10;
}
- scale = 1.0;
+ frac = (uint64_t) ((f - (double) ui64) * scale + 0.5);
- for (n = frac_width; n; n--) {
- scale *= 10.0;
+ if (frac == scale) {
+ ui64++;
+ frac = 0;
}
+ }
- /*
- * (int64_t) cast is required for msvc6:
- * it cannot convert uint64_t to double
- */
- ui64 = (uint64_t) ((f - (int64_t) ui64) * scale + 0.5);
+ buf = ngx_sprintf_num(buf, last, ui64, zero, 0, width);
+
+ if (frac_width) {
+ if (buf < last) {
+ *buf++ = '.';
+ }
- buf = ngx_sprintf_num(buf, last, ui64, '0', 0, frac_width);
+ buf = ngx_sprintf_num(buf, last, frac, '0', 0, frac_width);
}
fmt++;
@@ -1841,9 +1844,9 @@ ngx_strip_chroot(ngx_str_t *path)
{
if (!ngx_strncmp(path->data, NGX_PREFIX, strlen(NGX_PREFIX))) {
char *x, *buf = malloc(path->len);
- x = ngx_cpystrn(buf, path->data + strlen(NGX_PREFIX) - 1,
- path->len);
- path->len = (x - buf);
- path->data = buf;
+ x = ngx_cpystrn(buf, path->data + strlen(NGX_PREFIX) - 1,
+ path->len);
+ path->len = (x - buf);
+ path->data = buf;
}
}
diff --git a/usr.sbin/nginx/src/core/ngx_times.c b/usr.sbin/nginx/src/core/ngx_times.c
index 6a5808fe2ea..ed1bf64bc08 100644
--- a/usr.sbin/nginx/src/core/ngx_times.c
+++ b/usr.sbin/nginx/src/core/ngx_times.c
@@ -33,7 +33,7 @@ volatile ngx_str_t ngx_cached_http_log_iso8601;
#if !(NGX_WIN32)
/*
- * locatime() and localtime_r() are not Async-Signal-Safe functions, therefore,
+ * localtime() and localtime_r() are not Async-Signal-Safe functions, therefore,
* they must not be called by a signal handler, so we use the cached
* GMT offset value. Fortunately the value is changed only two times a year.
*/
@@ -308,7 +308,7 @@ ngx_gmtime(time_t t, ngx_tm_t *tp)
/*
* The "days" should be adjusted to 1 only, however, some March 1st's go
* to previous year, so we adjust them to 2. This causes also shift of the
- * last Feburary days to next year, but we catch the case when "yday"
+ * last February days to next year, but we catch the case when "yday"
* becomes negative.
*/
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 ddf178927b4..a73394906d1 100644
--- a/usr.sbin/nginx/src/event/modules/ngx_epoll_module.c
+++ b/usr.sbin/nginx/src/event/modules/ngx_epoll_module.c
@@ -445,7 +445,7 @@ ngx_epoll_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
/*
* when the file descriptor is closed, the epoll automatically deletes
- * it from its queue, so we do not need to delete explicity the event
+ * it from its queue, so we do not need to delete explicitly the event
* before the closing the file descriptor
*/
@@ -524,7 +524,7 @@ ngx_epoll_del_connection(ngx_connection_t *c, ngx_uint_t flags)
/*
* when the file descriptor is closed the epoll automatically deletes
- * it from its queue so we do not need to delete explicity the event
+ * it from its queue so we do not need to delete explicitly the event
* before the closing the file descriptor
*/
diff --git a/usr.sbin/nginx/src/event/modules/ngx_eventport_module.c b/usr.sbin/nginx/src/event/modules/ngx_eventport_module.c
index 0bfb47e5ca3..bbcd6dd6bae 100644
--- a/usr.sbin/nginx/src/event/modules/ngx_eventport_module.c
+++ b/usr.sbin/nginx/src/event/modules/ngx_eventport_module.c
@@ -322,7 +322,7 @@ ngx_eventport_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
/*
* when the file descriptor is closed, the event port automatically
- * dissociates it from the port, so we do not need to dissociate explicity
+ * dissociates it from the port, so we do not need to dissociate explicitly
* the event before the closing the file descriptor
*/
diff --git a/usr.sbin/nginx/src/event/modules/ngx_kqueue_module.c b/usr.sbin/nginx/src/event/modules/ngx_kqueue_module.c
index c0f70752f01..30e456c4da0 100644
--- a/usr.sbin/nginx/src/event/modules/ngx_kqueue_module.c
+++ b/usr.sbin/nginx/src/event/modules/ngx_kqueue_module.c
@@ -377,7 +377,7 @@ ngx_kqueue_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
/*
* when the file descriptor is closed the kqueue automatically deletes
- * its filters so we do not need to delete explicity the event
+ * its filters so we do not need to delete explicitly the event
* before the closing the file descriptor.
*/
diff --git a/usr.sbin/nginx/src/event/ngx_event.c b/usr.sbin/nginx/src/event/ngx_event.c
index 88e151cc4b5..a0a9d743b5e 100644
--- a/usr.sbin/nginx/src/event/ngx_event.c
+++ b/usr.sbin/nginx/src/event/ngx_event.c
@@ -21,6 +21,7 @@ extern ngx_module_t ngx_rtsig_module;
extern ngx_module_t ngx_select_module;
+static char *ngx_event_init_conf(ngx_cycle_t *cycle, void *conf);
static ngx_int_t ngx_event_module_init(ngx_cycle_t *cycle);
static ngx_int_t ngx_event_process_init(ngx_cycle_t *cycle);
static char *ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
@@ -31,8 +32,8 @@ static char *ngx_event_use(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static char *ngx_event_debug_connection(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
-static void *ngx_event_create_conf(ngx_cycle_t *cycle);
-static char *ngx_event_init_conf(ngx_cycle_t *cycle, void *conf);
+static void *ngx_event_core_create_conf(ngx_cycle_t *cycle);
+static char *ngx_event_core_init_conf(ngx_cycle_t *cycle, void *conf);
static ngx_uint_t ngx_timer_resolution;
@@ -93,7 +94,7 @@ static ngx_command_t ngx_events_commands[] = {
static ngx_core_module_t ngx_events_module_ctx = {
ngx_string("events"),
NULL,
- NULL
+ ngx_event_init_conf
};
@@ -173,8 +174,8 @@ static ngx_command_t ngx_event_core_commands[] = {
ngx_event_module_t ngx_event_core_module_ctx = {
&event_core_name,
- ngx_event_create_conf, /* create configuration */
- ngx_event_init_conf, /* init configuration */
+ ngx_event_core_create_conf, /* create configuration */
+ ngx_event_core_init_conf, /* init configuration */
{ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
};
@@ -423,6 +424,19 @@ ngx_handle_write_event(ngx_event_t *wev, size_t lowat)
}
+static char *
+ngx_event_init_conf(ngx_cycle_t *cycle, void *conf)
+{
+ if (ngx_get_conf(cycle->conf_ctx, ngx_events_module) == NULL) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
+ "no \"events\" section in configuration");
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
static ngx_int_t
ngx_event_module_init(ngx_cycle_t *cycle)
{
@@ -435,13 +449,6 @@ ngx_event_module_init(ngx_cycle_t *cycle)
ngx_event_conf_t *ecf;
cf = ngx_get_conf(cycle->conf_ctx, ngx_events_module);
-
- if (cf == NULL) {
- ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
- "no \"events\" section in configuration");
- return NGX_ERROR;
- }
-
ecf = (*cf)[ngx_event_core_module.ctx_index];
if (!ngx_test_config && ngx_process <= NGX_PROCESS_MASTER) {
@@ -471,7 +478,7 @@ ngx_event_module_init(ngx_cycle_t *cycle)
(ngx_int_t) rlmt.rlim_cur : ccf->rlimit_nofile;
ngx_log_error(NGX_LOG_WARN, cycle->log, 0,
- "%ui worker_connections are more than "
+ "%ui worker_connections exceed "
"open file resource limit: %i",
ecf->connections, limit);
}
@@ -489,7 +496,7 @@ ngx_event_module_init(ngx_cycle_t *cycle)
}
- /* cl should be equal or bigger than cache line size */
+ /* cl should be equal to or greater than cache line size */
cl = 128;
@@ -522,7 +529,8 @@ ngx_event_module_init(ngx_cycle_t *cycle)
ngx_accept_mutex_ptr = (ngx_atomic_t *) shared;
ngx_accept_mutex.spin = (ngx_uint_t) -1;
- if (ngx_shmtx_create(&ngx_accept_mutex, shared, cycle->lock_file.data)
+ if (ngx_shmtx_create(&ngx_accept_mutex, (ngx_shmtx_sh_t *) shared,
+ cycle->lock_file.data)
!= NGX_OK)
{
return NGX_ERROR;
@@ -1115,7 +1123,7 @@ ngx_event_debug_connection(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
static void *
-ngx_event_create_conf(ngx_cycle_t *cycle)
+ngx_event_core_create_conf(ngx_cycle_t *cycle)
{
ngx_event_conf_t *ecf;
@@ -1146,7 +1154,7 @@ ngx_event_create_conf(ngx_cycle_t *cycle)
static char *
-ngx_event_init_conf(ngx_cycle_t *cycle, void *conf)
+ngx_event_core_init_conf(ngx_cycle_t *cycle, void *conf)
{
ngx_event_conf_t *ecf = conf;
diff --git a/usr.sbin/nginx/src/event/ngx_event_openssl.c b/usr.sbin/nginx/src/event/ngx_event_openssl.c
index 6b9dba16b71..21deefda926 100644
--- a/usr.sbin/nginx/src/event/ngx_event_openssl.c
+++ b/usr.sbin/nginx/src/event/ngx_event_openssl.c
@@ -478,6 +478,7 @@ ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file)
return NGX_OK;
}
+
ngx_int_t
ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name)
{
@@ -488,7 +489,7 @@ ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name)
/*
* Elliptic-Curve Diffie-Hellman parameters are either "named curves"
- * from RFC 4492 section 5.1.1, or explicitely described curves over
+ * from RFC 4492 section 5.1.1, or explicitly described curves over
* binary fields. OpenSSL only supports the "named curves", which provide
* maximum interoperability.
*/
@@ -518,6 +519,7 @@ ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name)
return NGX_OK;
}
+
ngx_int_t
ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags)
{
diff --git a/usr.sbin/nginx/src/event/ngx_event_pipe.c b/usr.sbin/nginx/src/event/ngx_event_pipe.c
index 7af5a63fc24..c2c79837fcf 100644
--- a/usr.sbin/nginx/src/event/ngx_event_pipe.c
+++ b/usr.sbin/nginx/src/event/ngx_event_pipe.c
@@ -16,8 +16,6 @@ static ngx_int_t ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p);
static ngx_int_t ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p);
static ngx_inline void ngx_event_pipe_remove_shadow_links(ngx_buf_t *buf);
-static ngx_inline void ngx_event_pipe_free_shadow_raw_buf(ngx_chain_t **free,
- ngx_buf_t *buf);
static ngx_int_t ngx_event_pipe_drain_chains(ngx_event_pipe_t *p);
@@ -150,7 +148,7 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p)
&& p->upstream->read->pending_eof)
{
p->upstream->read->ready = 0;
- p->upstream->read->eof = 0;
+ p->upstream->read->eof = 1;
p->upstream_eof = 1;
p->read = 1;
@@ -393,8 +391,33 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p)
cl->buf->file_last - cl->buf->file_pos);
}
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0,
+ "pipe length: %O", p->length);
+
#endif
+ if (p->free_raw_bufs && p->length != -1) {
+ cl = p->free_raw_bufs;
+
+ if (cl->buf->last - cl->buf->pos >= p->length) {
+
+ p->free_raw_bufs = cl->next;
+
+ /* STUB */ cl->buf->num = p->num++;
+
+ if (p->input_filter(p, cl->buf) == NGX_ERROR) {
+ return NGX_ABORT;
+ }
+
+ ngx_free_chain(p->pool, cl);
+ }
+ }
+
+ if (p->length == 0) {
+ p->upstream_done = 1;
+ p->read = 1;
+ }
+
if ((p->upstream_eof || p->upstream_error) && p->free_raw_bufs) {
/* STUB */ p->free_raw_bufs->buf->num = p->num++;
@@ -553,17 +576,13 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p)
if (p->out) {
cl = p->out;
- if (cl->buf->recycled
- && bsize + cl->buf->last - cl->buf->pos > p->busy_size)
- {
- flush = 1;
- break;
+ if (cl->buf->recycled) {
+ ngx_log_error(NGX_LOG_ALERT, p->log, 0,
+ "recycled buffer in pipe out chain");
}
p->out = p->out->next;
- ngx_event_pipe_free_shadow_raw_buf(&p->free_raw_bufs, cl->buf);
-
} else if (!p->cacheable && p->in) {
cl = p->in;
@@ -573,24 +592,13 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p)
cl->buf->pos,
cl->buf->last - cl->buf->pos);
- if (cl->buf->recycled
- && cl->buf->last_shadow
- && bsize + cl->buf->last - cl->buf->pos > p->busy_size)
- {
- if (!prev_last_shadow) {
- p->in = p->in->next;
-
- cl->next = NULL;
-
- if (out) {
- *ll = cl;
- } else {
- out = cl;
- }
+ if (cl->buf->recycled && prev_last_shadow) {
+ if (bsize + cl->buf->end - cl->buf->start > p->busy_size) {
+ flush = 1;
+ break;
}
- flush = 1;
- break;
+ bsize += cl->buf->end - cl->buf->start;
}
prev_last_shadow = cl->buf->last_shadow;
@@ -601,10 +609,6 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p)
break;
}
- if (cl->buf->recycled) {
- bsize += cl->buf->last - cl->buf->pos;
- }
-
cl->next = NULL;
if (out) {
@@ -634,7 +638,7 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p)
rc = p->output_filter(p->output_ctx, out);
- ngx_chain_update_chains(&p->free, &p->busy, &out, p->tag);
+ ngx_chain_update_chains(p->pool, &p->free, &p->busy, &out, p->tag);
if (rc == NGX_ERROR) {
p->downstream_error = 1;
@@ -678,9 +682,10 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p)
static ngx_int_t
ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p)
{
- ssize_t size, bsize;
+ ssize_t size, bsize, n;
ngx_buf_t *b;
- ngx_chain_t *cl, *tl, *next, *out, **ll, **last_free, fl;
+ ngx_uint_t prev_last_shadow;
+ ngx_chain_t *cl, *tl, *next, *out, **ll, **last_out, **last_free, fl;
if (p->buf_to_file) {
fl.buf = p->buf_to_file;
@@ -696,6 +701,7 @@ ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p)
size = 0;
cl = out;
ll = NULL;
+ prev_last_shadow = 1;
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0,
"pipe offset: %O", p->temp_file->offset);
@@ -703,16 +709,21 @@ ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p)
do {
bsize = cl->buf->last - cl->buf->pos;
- ngx_log_debug3(NGX_LOG_DEBUG_EVENT, p->log, 0,
- "pipe buf %p, pos %p, size: %z",
- cl->buf->start, cl->buf->pos, bsize);
+ ngx_log_debug4(NGX_LOG_DEBUG_EVENT, p->log, 0,
+ "pipe buf ls:%d %p, pos %p, size: %z",
+ cl->buf->last_shadow, cl->buf->start,
+ cl->buf->pos, bsize);
- if ((size + bsize > p->temp_file_write_size)
- || (p->temp_file->offset + size + bsize > p->max_temp_file_size))
+ if (prev_last_shadow
+ && ((size + bsize > p->temp_file_write_size)
+ || (p->temp_file->offset + size + bsize
+ > p->max_temp_file_size)))
{
break;
}
+ prev_last_shadow = cl->buf->last_shadow;
+
size += bsize;
ll = &cl->next;
cl = cl->next;
@@ -739,42 +750,77 @@ ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p)
p->last_in = &p->in;
}
- if (ngx_write_chain_to_temp_file(p->temp_file, out) == NGX_ERROR) {
- return NGX_ABORT;
- }
+ n = ngx_write_chain_to_temp_file(p->temp_file, out);
- for (last_free = &p->free_raw_bufs;
- *last_free != NULL;
- last_free = &(*last_free)->next)
- {
- /* void */
+ if (n == NGX_ERROR) {
+ return NGX_ABORT;
}
if (p->buf_to_file) {
p->temp_file->offset = p->buf_to_file->last - p->buf_to_file->pos;
+ n -= p->buf_to_file->last - p->buf_to_file->pos;
p->buf_to_file = NULL;
out = out->next;
}
- for (cl = out; cl; cl = next) {
- next = cl->next;
- cl->next = NULL;
+ if (n > 0) {
+ /* update previous buffer or add new buffer */
+
+ if (p->out) {
+ for (cl = p->out; cl->next; cl = cl->next) { /* void */ }
+
+ b = cl->buf;
+
+ if (b->file_last == p->temp_file->offset) {
+ p->temp_file->offset += n;
+ b->file_last = p->temp_file->offset;
+ goto free;
+ }
+
+ last_out = &cl->next;
+
+ } else {
+ last_out = &p->out;
+ }
+
+ cl = ngx_chain_get_free_buf(p->pool, &p->free);
+ if (cl == NULL) {
+ return NGX_ABORT;
+ }
b = cl->buf;
+
+ ngx_memzero(b, sizeof(ngx_buf_t));
+
+ b->tag = p->tag;
+
b->file = &p->temp_file->file;
b->file_pos = p->temp_file->offset;
- p->temp_file->offset += b->last - b->pos;
+ p->temp_file->offset += n;
b->file_last = p->temp_file->offset;
b->in_file = 1;
b->temp_file = 1;
- if (p->out) {
- *p->last_out = cl;
- } else {
- p->out = cl;
- }
- p->last_out = &cl->next;
+ *last_out = cl;
+ }
+
+free:
+
+ for (last_free = &p->free_raw_bufs;
+ *last_free != NULL;
+ last_free = &(*last_free)->next)
+ {
+ /* void */
+ }
+
+ for (cl = out; cl; cl = next) {
+ next = cl->next;
+
+ cl->next = p->free;
+ p->free = cl;
+
+ b = cl->buf;
if (b->last_shadow) {
@@ -849,6 +895,12 @@ ngx_event_pipe_copy_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
}
p->last_in = &cl->next;
+ if (p->length == -1) {
+ return NGX_OK;
+ }
+
+ p->length -= b->last - b->pos;
+
return NGX_OK;
}
@@ -884,35 +936,6 @@ ngx_event_pipe_remove_shadow_links(ngx_buf_t *buf)
}
-static ngx_inline void
-ngx_event_pipe_free_shadow_raw_buf(ngx_chain_t **free, ngx_buf_t *buf)
-{
- ngx_buf_t *s;
- ngx_chain_t *cl, **ll;
-
- if (buf->shadow == NULL) {
- return;
- }
-
- for (s = buf->shadow; !s->last_shadow; s = s->shadow) { /* void */ }
-
- ll = free;
-
- for (cl = *free; cl; cl = cl->next) {
- if (cl->buf == s) {
- *ll = cl->next;
- break;
- }
-
- if (cl->buf->shadow) {
- break;
- }
-
- ll = &cl->next;
- }
-}
-
-
ngx_int_t
ngx_event_pipe_add_free_buf(ngx_event_pipe_t *p, ngx_buf_t *b)
{
diff --git a/usr.sbin/nginx/src/event/ngx_event_pipe.h b/usr.sbin/nginx/src/event/ngx_event_pipe.h
index ff63cf64af3..f24e6d148f5 100644
--- a/usr.sbin/nginx/src/event/ngx_event_pipe.h
+++ b/usr.sbin/nginx/src/event/ngx_event_pipe.h
@@ -31,8 +31,6 @@ struct ngx_event_pipe_s {
ngx_chain_t **last_in;
ngx_chain_t *out;
- ngx_chain_t **last_out;
-
ngx_chain_t *free;
ngx_chain_t *busy;
@@ -66,6 +64,7 @@ struct ngx_event_pipe_s {
ssize_t busy_size;
off_t read_length;
+ off_t length;
off_t max_temp_file_size;
ssize_t temp_file_write_size;
diff --git a/usr.sbin/nginx/src/event/ngx_event_timer.c b/usr.sbin/nginx/src/event/ngx_event_timer.c
index 7a810720930..177ac1cf113 100644
--- a/usr.sbin/nginx/src/event/ngx_event_timer.c
+++ b/usr.sbin/nginx/src/event/ngx_event_timer.c
@@ -67,7 +67,7 @@ ngx_event_find_timer(void)
ngx_mutex_unlock(ngx_event_timer_mutex);
- timer = (ngx_msec_int_t) node->key - (ngx_msec_int_t) ngx_current_msec;
+ timer = (ngx_msec_int_t) (node->key - ngx_current_msec);
return (ngx_msec_t) (timer > 0 ? timer : 0);
}
@@ -95,8 +95,7 @@ ngx_event_expire_timers(void)
/* node->key <= ngx_current_time */
- if ((ngx_msec_int_t) node->key - (ngx_msec_int_t) ngx_current_msec <= 0)
- {
+ if ((ngx_msec_int_t) (node->key - ngx_current_msec) <= 0) {
ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer));
#if (NGX_THREADS)
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 84a75d777ab..70a4262fccb 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
@@ -351,14 +351,19 @@ 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->rules = prev->rules;
+ conf->rules6 = prev->rules6;
}
-#if (NGX_HAVE_INET6)
- if (conf->rules6 == NULL) {
- conf->rules6 = prev->rules6;
+#else
+
+ if (conf->rules == NULL) {
+ conf->rules = prev->rules;
}
+
#endif
return NGX_CONF_OK;
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_browser_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_browser_module.c
index 13a7145385e..80da0d8fa86 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_browser_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_browser_module.c
@@ -458,10 +458,11 @@ ngx_http_browser_merge_conf(ngx_conf_t *cf, void *parent, void *child)
* with a real skip value. The zero value means Opera.
*/
- if (conf->modern_browsers == NULL) {
+ if (conf->modern_browsers == NULL && conf->modern_unlisted_browsers == 0) {
conf->modern_browsers = prev->modern_browsers;
+ conf->modern_unlisted_browsers = prev->modern_unlisted_browsers;
- } else {
+ } else if (conf->modern_browsers != NULL) {
browsers = conf->modern_browsers->elts;
for (i = 0; i < conf->modern_browsers->nelts; i++) {
@@ -501,8 +502,9 @@ found:
}
}
- if (conf->ancient_browsers == NULL) {
+ if (conf->ancient_browsers == NULL && conf->netscape4 == 0) {
conf->ancient_browsers = prev->ancient_browsers;
+ conf->netscape4 = prev->netscape4;
}
if (conf->modern_browser_value == NULL) {
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_chunked_filter_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_chunked_filter_module.c
index f07a8442e4d..94313a8f650 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_chunked_filter_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_chunked_filter_module.c
@@ -222,7 +222,7 @@ ngx_http_chunked_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
rc = ngx_http_next_body_filter(r, out);
- ngx_chain_update_chains(&ctx->free, &ctx->busy, &out,
+ ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out,
(ngx_buf_tag_t) &ngx_http_chunked_filter_module);
return rc;
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_degradation_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_degradation_module.c
index 0b1368f3b5a..b9c65cdc9e0 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_degradation_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_degradation_module.c
@@ -126,7 +126,7 @@ ngx_http_degraded(ngx_http_request_t *r)
* ELF/i386 is loaded at 0x08000000, 128M
* ELF/amd64 is loaded at 0x00400000, 4M
*
- * use a function address to substract the loading address
+ * use a function address to subtract the loading address
*/
sbrk_size = (size_t) sbrk(0) - ((uintptr_t) ngx_palloc & ~0x3FFFFF);
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 23ef2957f6b..3bc994a8004 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
@@ -27,6 +27,8 @@ typedef struct {
ngx_hash_t headers_hash;
ngx_uint_t header_params;
+ ngx_flag_t keep_conn;
+
#if (NGX_HTTP_CACHE)
ngx_http_complex_value_t cache_key;
#endif
@@ -78,6 +80,8 @@ typedef struct {
#define NGX_HTTP_FASTCGI_RESPONDER 1
+#define NGX_HTTP_FASTCGI_KEEP_CONN 1
+
#define NGX_HTTP_FASTCGI_BEGIN_REQUEST 1
#define NGX_HTTP_FASTCGI_ABORT_REQUEST 2
#define NGX_HTTP_FASTCGI_END_REQUEST 3
@@ -131,6 +135,7 @@ static ngx_int_t ngx_http_fastcgi_create_key(ngx_http_request_t *r);
static ngx_int_t ngx_http_fastcgi_create_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_fastcgi_reinit_request(ngx_http_request_t *r);
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_process_record(ngx_http_request_t *r,
@@ -376,6 +381,20 @@ static ngx_command_t ngx_http_fastcgi_commands[] = {
offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_methods),
&ngx_http_upstream_cache_method_mask },
+ { ngx_string("fastcgi_cache_lock"),
+ 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_lock),
+ NULL },
+
+ { ngx_string("fastcgi_cache_lock_timeout"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_msec_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_lock_timeout),
+ NULL },
+
#endif
{ ngx_string("fastcgi_temp_path"),
@@ -407,8 +426,8 @@ static ngx_command_t ngx_http_fastcgi_commands[] = {
&ngx_http_fastcgi_next_upstream_masks },
{ ngx_string("fastcgi_param"),
- NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
- ngx_conf_set_keyval_slot,
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE23,
+ ngx_http_upstream_param_set_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_fastcgi_loc_conf_t, params_source),
NULL },
@@ -441,6 +460,13 @@ static ngx_command_t ngx_http_fastcgi_commands[] = {
offsetof(ngx_http_fastcgi_loc_conf_t, catch_stderr),
NULL },
+ { ngx_string("fastcgi_keep_conn"),
+ 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, keep_conn),
+ NULL },
+
ngx_null_command
};
@@ -604,6 +630,8 @@ ngx_http_fastcgi_handler(ngx_http_request_t *r)
u->pipe->input_filter = ngx_http_fastcgi_input_filter;
u->pipe->input_ctx = r;
+ u->input_filter_init = ngx_http_fastcgi_input_filter_init;
+
rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
@@ -695,7 +723,7 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r)
u_char ch, *pos, *lowcase_key;
size_t size, len, key_len, val_len, padding,
allocated;
- ngx_uint_t i, n, next, hash, header_params;
+ ngx_uint_t i, n, next, hash, skip_empty, header_params;
ngx_buf_t *b;
ngx_chain_t *cl, *body;
ngx_list_part_t *part;
@@ -726,11 +754,18 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r)
lcode = *(ngx_http_script_len_code_pt *) le.ip;
key_len = lcode(&le);
+ lcode = *(ngx_http_script_len_code_pt *) le.ip;
+ skip_empty = lcode(&le);
+
for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
lcode = *(ngx_http_script_len_code_pt *) le.ip;
}
le.ip += sizeof(uintptr_t);
+ if (skip_empty && val_len == 0) {
+ continue;
+ }
+
len += 1 + key_len + ((val_len > 127) ? 4 : 1) + val_len;
}
}
@@ -845,6 +880,9 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r)
cl->buf = b;
+ ngx_http_fastcgi_request_start.br.flags =
+ flcf->keep_conn ? NGX_HTTP_FASTCGI_KEEP_CONN : 0;
+
ngx_memcpy(b->pos, &ngx_http_fastcgi_request_start,
sizeof(ngx_http_fastcgi_request_start_t));
@@ -877,11 +915,28 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r)
lcode = *(ngx_http_script_len_code_pt *) le.ip;
key_len = (u_char) lcode(&le);
+ lcode = *(ngx_http_script_len_code_pt *) le.ip;
+ skip_empty = lcode(&le);
+
for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
lcode = *(ngx_http_script_len_code_pt *) le.ip;
}
le.ip += sizeof(uintptr_t);
+ if (skip_empty && val_len == 0) {
+ e.skip = 1;
+
+ while (*(uintptr_t *) e.ip) {
+ code = *(ngx_http_script_code_pt *) e.ip;
+ code((ngx_http_script_engine_t *) &e);
+ }
+ e.ip += sizeof(uintptr_t);
+
+ e.skip = 0;
+
+ continue;
+ }
+
*e.pos++ = (u_char) key_len;
if (val_len > 127) {
@@ -1199,7 +1254,7 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r)
if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
- "upstream closed prematurely FastCGI stdout");
+ "upstream prematurely closed FastCGI stdout");
return NGX_HTTP_UPSTREAM_INVALID_HEADER;
}
@@ -1578,14 +1633,30 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r)
static ngx_int_t
+ngx_http_fastcgi_input_filter_init(void *data)
+{
+ ngx_http_request_t *r = data;
+ ngx_http_fastcgi_loc_conf_t *flcf;
+
+ flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
+
+ r->upstream->pipe->length = flcf->keep_conn ?
+ (off_t) sizeof(ngx_http_fastcgi_header_t) : -1;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
{
- u_char *m, *msg;
- ngx_int_t rc;
- ngx_buf_t *b, **prev;
- ngx_chain_t *cl;
- ngx_http_request_t *r;
- ngx_http_fastcgi_ctx_t *f;
+ u_char *m, *msg;
+ ngx_int_t rc;
+ ngx_buf_t *b, **prev;
+ ngx_chain_t *cl;
+ ngx_http_request_t *r;
+ ngx_http_fastcgi_ctx_t *f;
+ ngx_http_fastcgi_loc_conf_t *flcf;
if (buf->pos == buf->last) {
return NGX_OK;
@@ -1593,6 +1664,7 @@ ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
r = p->input_ctx;
f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
+ flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
b = NULL;
prev = &buf->shadow;
@@ -1615,7 +1687,10 @@ ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) {
f->state = ngx_http_fastcgi_st_version;
- p->upstream_done = 1;
+
+ if (!flcf->keep_conn) {
+ p->upstream_done = 1;
+ }
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
"http fastcgi closed stdout");
@@ -1627,6 +1702,10 @@ ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
f->state = ngx_http_fastcgi_st_version;
p->upstream_done = 1;
+ if (flcf->keep_conn) {
+ r->upstream->keepalive = 1;
+ }
+
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
"http fastcgi sent end request");
@@ -1787,6 +1866,23 @@ ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
}
+ if (flcf->keep_conn) {
+
+ /* set p->length, minimal amount of data we want to see */
+
+ if (f->state < ngx_http_fastcgi_st_data) {
+ p->length = 1;
+
+ } else if (f->state == ngx_http_fastcgi_st_padding) {
+ p->length = f->padding;
+
+ } else {
+ /* ngx_http_fastcgi_st_data */
+
+ p->length = f->length;
+ }
+ }
+
if (b) {
b->shadow = buf;
b->last_shadow = 1;
@@ -2005,6 +2101,8 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
+ conf->upstream.cache_lock = NGX_CONF_UNSET;
+ conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
#endif
conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
@@ -2017,6 +2115,8 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
conf->catch_stderr = NGX_CONF_UNSET_PTR;
+ conf->keep_conn = NGX_CONF_UNSET;
+
ngx_str_set(&conf->upstream.module, "fastcgi");
return conf;
@@ -2098,8 +2198,8 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
if (conf->upstream.busy_buffers_size < size) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "\"fastcgi_busy_buffers_size\" must be equal or bigger than "
- "maximum of the value of \"fastcgi_buffer_size\" and "
+ "\"fastcgi_busy_buffers_size\" must be equal to or greater than "
+ "the maximum of the value of \"fastcgi_buffer_size\" and "
"one of the \"fastcgi_buffers\"");
return NGX_CONF_ERROR;
@@ -2129,8 +2229,8 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
if (conf->upstream.temp_file_write_size < size) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "\"fastcgi_temp_file_write_size\" must be equal or bigger than "
- "maximum of the value of \"fastcgi_buffer_size\" and "
+ "\"fastcgi_temp_file_write_size\" must be equal to or greater "
+ "than the maximum of the value of \"fastcgi_buffer_size\" and "
"one of the \"fastcgi_buffers\"");
return NGX_CONF_ERROR;
@@ -2153,8 +2253,8 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"fastcgi_max_temp_file_size\" must be equal to zero to disable "
- "the temporary files usage or must be equal or bigger than "
- "maximum of the value of \"fastcgi_buffer_size\" and "
+ "temporary files usage or must be equal to or greater than "
+ "the maximum of the value of \"fastcgi_buffer_size\" and "
"one of the \"fastcgi_buffers\"");
return NGX_CONF_ERROR;
@@ -2244,6 +2344,12 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
conf->cache_key = prev->cache_key;
}
+ ngx_conf_merge_value(conf->upstream.cache_lock,
+ prev->upstream.cache_lock, 0);
+
+ ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
+ prev->upstream.cache_lock_timeout, 5000);
+
#endif
ngx_conf_merge_value(conf->upstream.pass_request_headers,
@@ -2256,6 +2362,8 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_ptr_value(conf->catch_stderr, prev->catch_stderr, NULL);
+ ngx_conf_merge_value(conf->keep_conn, prev->keep_conn, 0);
+
ngx_conf_merge_str_value(conf->index, prev->index, "");
@@ -2313,9 +2421,9 @@ ngx_http_fastcgi_merge_params(ngx_conf_t *cf,
#if (NGX_HTTP_CACHE)
ngx_array_t params_merged;
#endif
- ngx_keyval_t *src;
ngx_hash_key_t *hk;
ngx_hash_init_t hash;
+ ngx_http_upstream_param_t *src;
ngx_http_script_compile_t sc;
ngx_http_script_copy_code_t *copy;
@@ -2324,7 +2432,8 @@ ngx_http_fastcgi_merge_params(ngx_conf_t *cf,
if (prev->headers_hash.buckets
#if (NGX_HTTP_CACHE)
- && ((conf->upstream.cache == NULL) == (prev->upstream.cache == NULL))
+ && ((conf->upstream.cache == NULL)
+ == (prev->upstream.cache == NULL))
#endif
)
{
@@ -2376,9 +2485,11 @@ ngx_http_fastcgi_merge_params(ngx_conf_t *cf,
#if (NGX_HTTP_CACHE)
if (conf->upstream.cache) {
- ngx_keyval_t *h, *s;
+ ngx_keyval_t *h;
+ ngx_http_upstream_param_t *s;
- if (ngx_array_init(&params_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t))
+ if (ngx_array_init(&params_merged, cf->temp_pool, 4,
+ sizeof(ngx_http_upstream_param_t))
!= NGX_OK)
{
return NGX_ERROR;
@@ -2412,7 +2523,9 @@ ngx_http_fastcgi_merge_params(ngx_conf_t *cf,
return NGX_ERROR;
}
- *s = *h;
+ s->key = h->key;
+ s->value = h->value;
+ s->skip_empty = 0;
next:
@@ -2454,6 +2567,15 @@ ngx_http_fastcgi_merge_params(ngx_conf_t *cf,
copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
copy->len = src[i].key.len;
+ copy = ngx_array_push_n(conf->params_len,
+ sizeof(ngx_http_script_copy_code_t));
+ if (copy == NULL) {
+ return NGX_ERROR;
+ }
+
+ copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
+ copy->len = src[i].skip_empty;
+
size = (sizeof(ngx_http_script_copy_code_t)
+ src[i].key.len + sizeof(uintptr_t) - 1)
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_flv_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_flv_module.c
index f6870235b34..719a0112499 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_flv_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_flv_module.c
@@ -110,6 +110,10 @@ ngx_http_flv_handler(ngx_http_request_t *r)
of.errors = clcf->open_file_cache_errors;
of.events = clcf->open_file_cache_events;
+ if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
!= NGX_OK)
{
@@ -127,6 +131,10 @@ ngx_http_flv_handler(ngx_http_request_t *r)
break;
case NGX_EACCES:
+#if (NGX_HAVE_OPENAT)
+ case NGX_EMLINK:
+ case NGX_ELOOP:
+#endif
level = NGX_LOG_ERR;
rc = NGX_HTTP_FORBIDDEN;
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_geo_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_geo_module.c
index 1d7599e5551..30b0e35a9aa 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_geo_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_geo_module.c
@@ -566,7 +566,7 @@ ngx_http_geo_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx,
if (ctx->binary_include) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "binary geo range base \"%s\" may not be mixed with usual entries",
+ "binary geo range base \"%s\" cannot be mixed with usual entries",
ctx->include_name.data);
return NGX_CONF_ERROR;
}
@@ -1195,7 +1195,7 @@ ngx_http_geo_include_binary_base(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx,
if (ctx->outside_entries) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "binary geo range base \"%s\" may not be mixed with usual entries",
+ "binary geo range base \"%s\" cannot be mixed with usual entries",
name->data);
rc = NGX_ERROR;
goto done;
@@ -1203,7 +1203,7 @@ ngx_http_geo_include_binary_base(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx,
if (ctx->binary_include) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "second binary geo range base \"%s\" may not be mixed with \"%s\"",
+ "second binary geo range base \"%s\" cannot be mixed with \"%s\"",
name->data, ctx->include_name.data);
rc = NGX_ERROR;
goto done;
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 dccc554a312..128d3d9c89d 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
@@ -379,7 +379,7 @@ ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
cl = NULL;
- ngx_chain_update_chains(&ctx->free, &ctx->busy, &cl,
+ ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &cl,
(ngx_buf_tag_t) &ngx_http_gzip_filter_module);
ctx->nomem = 0;
}
@@ -449,7 +449,7 @@ ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
ngx_http_gzip_filter_free_copy_buf(r, ctx);
- ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out,
+ ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &ctx->out,
(ngx_buf_tag_t) &ngx_http_gzip_filter_module);
ctx->last_out = &ctx->out;
@@ -759,6 +759,7 @@ static ngx_int_t
ngx_http_gzip_filter_deflate(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
{
int rc;
+ ngx_buf_t *b;
ngx_chain_t *cl;
ngx_http_gzip_conf_t *conf;
@@ -770,7 +771,7 @@ ngx_http_gzip_filter_deflate(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
rc = deflate(&ctx->zstream, ctx->flush);
- if (rc != Z_OK && rc != Z_STREAM_END) {
+ if (rc != Z_OK && rc != Z_STREAM_END && rc != Z_BUF_ERROR) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
"deflate() failed: %d, %d", ctx->flush, rc);
return NGX_ERROR;
@@ -819,8 +820,6 @@ ngx_http_gzip_filter_deflate(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
if (ctx->flush == Z_SYNC_FLUSH) {
- ctx->zstream.avail_out = 0;
- ctx->out_buf->flush = 1;
ctx->flush = Z_NO_FLUSH;
cl = ngx_alloc_chain_link(r->pool);
@@ -828,7 +827,22 @@ ngx_http_gzip_filter_deflate(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
return NGX_ERROR;
}
- cl->buf = ctx->out_buf;
+ b = ctx->out_buf;
+
+ if (ngx_buf_size(b) == 0) {
+
+ b = ngx_calloc_buf(ctx->request->pool);
+ if (b == NULL) {
+ return NGX_ERROR;
+ }
+
+ } else {
+ ctx->zstream.avail_out = 0;
+ }
+
+ b->flush = 1;
+
+ cl->buf = b;
cl->next = NULL;
*ctx->last_out = cl;
ctx->last_out = &cl->next;
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 18c28d8f581..46ce8f3f327 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
@@ -130,6 +130,10 @@ ngx_http_gzip_static_handler(ngx_http_request_t *r)
of.errors = clcf->open_file_cache_errors;
of.events = clcf->open_file_cache_events;
+ if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
!= NGX_OK)
{
@@ -145,6 +149,10 @@ ngx_http_gzip_static_handler(ngx_http_request_t *r)
return NGX_DECLINED;
case NGX_EACCES:
+#if (NGX_HAVE_OPENAT)
+ case NGX_EMLINK:
+ case NGX_ELOOP:
+#endif
level = NGX_LOG_ERR;
break;
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 a7065946305..93899343437 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
@@ -25,23 +25,25 @@ typedef struct {
struct ngx_http_header_val_s {
ngx_http_complex_value_t value;
- ngx_uint_t hash;
ngx_str_t key;
ngx_http_set_header_pt handler;
ngx_uint_t offset;
};
-#define NGX_HTTP_EXPIRES_OFF 0
-#define NGX_HTTP_EXPIRES_EPOCH 1
-#define NGX_HTTP_EXPIRES_MAX 2
-#define NGX_HTTP_EXPIRES_ACCESS 3
-#define NGX_HTTP_EXPIRES_MODIFIED 4
-#define NGX_HTTP_EXPIRES_DAILY 5
+typedef enum {
+ NGX_HTTP_EXPIRES_OFF,
+ NGX_HTTP_EXPIRES_EPOCH,
+ NGX_HTTP_EXPIRES_MAX,
+ NGX_HTTP_EXPIRES_ACCESS,
+ NGX_HTTP_EXPIRES_MODIFIED,
+ NGX_HTTP_EXPIRES_DAILY,
+ NGX_HTTP_EXPIRES_UNSET
+} ngx_http_expires_t;
typedef struct {
- ngx_uint_t expires;
+ ngx_http_expires_t expires;
time_t expires_time;
ngx_array_t *headers;
} ngx_http_headers_conf_t;
@@ -51,6 +53,8 @@ static ngx_int_t ngx_http_set_expires(ngx_http_request_t *r,
ngx_http_headers_conf_t *conf);
static ngx_int_t ngx_http_add_cache_control(ngx_http_request_t *r,
ngx_http_header_val_t *hv, ngx_str_t *value);
+static ngx_int_t ngx_http_add_header(ngx_http_request_t *r,
+ ngx_http_header_val_t *hv, ngx_str_t *value);
static ngx_int_t ngx_http_set_last_modified(ngx_http_request_t *r,
ngx_http_header_val_t *hv, ngx_str_t *value);
@@ -313,7 +317,7 @@ ngx_http_add_header(ngx_http_request_t *r, ngx_http_header_val_t *hv,
return NGX_ERROR;
}
- h->hash = hv->hash;
+ h->hash = 1;
h->key = hv->key;
h->value = *value;
}
@@ -366,16 +370,11 @@ ngx_http_set_last_modified(ngx_http_request_t *r, ngx_http_header_val_t *hv,
{
ngx_table_elt_t *h, **old;
- if (hv->offset) {
- old = (ngx_table_elt_t **) ((char *) &r->headers_out + hv->offset);
-
- } else {
- old = NULL;
- }
+ old = (ngx_table_elt_t **) ((char *) &r->headers_out + hv->offset);
r->headers_out.last_modified_time = -1;
- if (old == NULL || *old == NULL) {
+ if (*old == NULL) {
if (value->len == 0) {
return NGX_OK;
@@ -386,6 +385,8 @@ ngx_http_set_last_modified(ngx_http_request_t *r, ngx_http_header_val_t *hv,
return NGX_ERROR;
}
+ *old = h;
+
} else {
h = *old;
@@ -395,7 +396,7 @@ ngx_http_set_last_modified(ngx_http_request_t *r, ngx_http_header_val_t *hv,
}
}
- h->hash = hv->hash;
+ h->hash = 1;
h->key = hv->key;
h->value = *value;
@@ -420,7 +421,7 @@ ngx_http_headers_create_conf(ngx_conf_t *cf)
* conf->expires_time = 0;
*/
- conf->expires = NGX_CONF_UNSET_UINT;
+ conf->expires = NGX_HTTP_EXPIRES_UNSET;
return conf;
}
@@ -432,11 +433,11 @@ ngx_http_headers_merge_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_http_headers_conf_t *prev = parent;
ngx_http_headers_conf_t *conf = child;
- if (conf->expires == NGX_CONF_UNSET_UINT) {
+ if (conf->expires == NGX_HTTP_EXPIRES_UNSET) {
conf->expires = prev->expires;
conf->expires_time = prev->expires_time;
- if (conf->expires == NGX_CONF_UNSET_UINT) {
+ if (conf->expires == NGX_HTTP_EXPIRES_UNSET) {
conf->expires = NGX_HTTP_EXPIRES_OFF;
}
}
@@ -467,7 +468,7 @@ ngx_http_headers_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ngx_uint_t minus, n;
ngx_str_t *value;
- if (hcf->expires != NGX_CONF_UNSET_UINT) {
+ if (hcf->expires != NGX_HTTP_EXPIRES_UNSET) {
return "is duplicate";
}
@@ -532,7 +533,7 @@ ngx_http_headers_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
hcf->expires_time = ngx_parse_time(&value[n], 1);
- if (hcf->expires_time == NGX_ERROR) {
+ if (hcf->expires_time == (time_t) NGX_ERROR) {
return "invalid value";
}
@@ -542,10 +543,6 @@ ngx_http_headers_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return "daily time value must be less than 24 hours";
}
- if (hcf->expires_time == NGX_PARSE_LARGE_TIME) {
- return "value must be less than 68 years";
- }
-
if (minus) {
hcf->expires_time = - hcf->expires_time;
}
@@ -580,7 +577,6 @@ ngx_http_headers_add(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return NGX_CONF_ERROR;
}
- hv->hash = 1;
hv->key = value[1];
hv->handler = ngx_http_add_header;
hv->offset = 0;
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 dd3c9cee5ae..c853c33d092 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
@@ -817,9 +817,7 @@ transparent:
resize = 0;
- if ((ngx_uint_t) (dx * 100 / dy)
- < ctx->max_width * 100 / ctx->max_height)
- {
+ if ((double) dx / dy < (double) ctx->max_width / ctx->max_height) {
if ((ngx_uint_t) dx > ctx->max_width) {
dy = dy * ctx->max_width / dx;
dy = dy ? dy : 1;
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_index_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_index_module.c
index 5d91b011820..cfe4ba6cc63 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_index_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_index_module.c
@@ -210,6 +210,10 @@ ngx_http_index_handler(ngx_http_request_t *r)
of.errors = clcf->open_file_cache_errors;
of.events = clcf->open_file_cache_events;
+ if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
!= NGX_OK)
{
@@ -220,6 +224,14 @@ ngx_http_index_handler(ngx_http_request_t *r)
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
+#if (NGX_HAVE_OPENAT)
+ if (of.err == NGX_EMLINK
+ || of.err == NGX_ELOOP)
+ {
+ return NGX_HTTP_FORBIDDEN;
+ }
+#endif
+
if (of.err == NGX_ENOTDIR
|| of.err == NGX_ENAMETOOLONG
|| of.err == NGX_EACCES)
@@ -297,11 +309,23 @@ ngx_http_index_test_dir(ngx_http_request_t *r, ngx_http_core_loc_conf_t *clcf,
of.valid = clcf->open_file_cache_valid;
of.errors = clcf->open_file_cache_errors;
+ if (ngx_http_set_disable_symlinks(r, clcf, &dir, &of) != NGX_OK) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
if (ngx_open_cached_file(clcf->open_file_cache, &dir, &of, r->pool)
!= NGX_OK)
{
if (of.err) {
+#if (NGX_HAVE_OPENAT)
+ if (of.err == NGX_EMLINK
+ || of.err == NGX_ELOOP)
+ {
+ return NGX_HTTP_FORBIDDEN;
+ }
+#endif
+
if (of.err == NGX_ENOENT) {
*last = c;
return ngx_http_index_error(r, clcf, dir.data, NGX_ENOENT);
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_limit_conn_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_limit_conn_module.c
new file mode 100644
index 00000000000..c23c046ed4d
--- /dev/null
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_limit_conn_module.c
@@ -0,0 +1,747 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+typedef struct {
+ u_char color;
+ u_char len;
+ u_short conn;
+ u_char data[1];
+} ngx_http_limit_conn_node_t;
+
+
+typedef struct {
+ ngx_shm_zone_t *shm_zone;
+ ngx_rbtree_node_t *node;
+} ngx_http_limit_conn_cleanup_t;
+
+
+typedef struct {
+ ngx_rbtree_t *rbtree;
+ ngx_int_t index;
+ ngx_str_t var;
+} ngx_http_limit_conn_ctx_t;
+
+
+typedef struct {
+ ngx_shm_zone_t *shm_zone;
+ ngx_uint_t conn;
+} ngx_http_limit_conn_limit_t;
+
+
+typedef struct {
+ ngx_array_t limits;
+ ngx_uint_t log_level;
+} ngx_http_limit_conn_conf_t;
+
+
+static ngx_rbtree_node_t *ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree,
+ ngx_http_variable_value_t *vv, uint32_t hash);
+static void ngx_http_limit_conn_cleanup(void *data);
+static ngx_inline void ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool);
+
+static void *ngx_http_limit_conn_create_conf(ngx_conf_t *cf);
+static char *ngx_http_limit_conn_merge_conf(ngx_conf_t *cf, void *parent,
+ void *child);
+static char *ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+static char *ngx_http_limit_zone(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+static char *ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+static ngx_int_t ngx_http_limit_conn_init(ngx_conf_t *cf);
+
+
+static ngx_conf_deprecated_t ngx_conf_deprecated_limit_zone = {
+ ngx_conf_deprecated, "limit_zone", "limit_conn_zone"
+};
+
+
+static ngx_conf_enum_t ngx_http_limit_conn_log_levels[] = {
+ { ngx_string("info"), NGX_LOG_INFO },
+ { ngx_string("notice"), NGX_LOG_NOTICE },
+ { ngx_string("warn"), NGX_LOG_WARN },
+ { ngx_string("error"), NGX_LOG_ERR },
+ { ngx_null_string, 0 }
+};
+
+
+static ngx_command_t ngx_http_limit_conn_commands[] = {
+
+ { ngx_string("limit_conn_zone"),
+ NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE2,
+ ngx_http_limit_conn_zone,
+ 0,
+ 0,
+ NULL },
+
+ { ngx_string("limit_zone"),
+ NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE3,
+ ngx_http_limit_zone,
+ 0,
+ 0,
+ NULL },
+
+ { ngx_string("limit_conn"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
+ ngx_http_limit_conn,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ 0,
+ NULL },
+
+ { ngx_string("limit_conn_log_level"),
+ 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_limit_conn_conf_t, log_level),
+ &ngx_http_limit_conn_log_levels },
+
+ ngx_null_command
+};
+
+
+static ngx_http_module_t ngx_http_limit_conn_module_ctx = {
+ NULL, /* preconfiguration */
+ ngx_http_limit_conn_init, /* postconfiguration */
+
+ NULL, /* create main configuration */
+ NULL, /* init main configuration */
+
+ NULL, /* create server configuration */
+ NULL, /* merge server configuration */
+
+ ngx_http_limit_conn_create_conf, /* create location configuration */
+ ngx_http_limit_conn_merge_conf /* merge location configuration */
+};
+
+
+ngx_module_t ngx_http_limit_conn_module = {
+ NGX_MODULE_V1,
+ &ngx_http_limit_conn_module_ctx, /* module context */
+ ngx_http_limit_conn_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_limit_conn_handler(ngx_http_request_t *r)
+{
+ size_t len, n;
+ uint32_t hash;
+ ngx_uint_t i;
+ ngx_slab_pool_t *shpool;
+ ngx_rbtree_node_t *node;
+ ngx_pool_cleanup_t *cln;
+ ngx_http_variable_value_t *vv;
+ ngx_http_limit_conn_ctx_t *ctx;
+ ngx_http_limit_conn_node_t *lc;
+ ngx_http_limit_conn_conf_t *lccf;
+ ngx_http_limit_conn_limit_t *limits;
+ ngx_http_limit_conn_cleanup_t *lccln;
+
+ if (r->main->limit_conn_set) {
+ return NGX_DECLINED;
+ }
+
+ lccf = ngx_http_get_module_loc_conf(r, ngx_http_limit_conn_module);
+ limits = lccf->limits.elts;
+
+ for (i = 0; i < lccf->limits.nelts; i++) {
+ ctx = limits[i].shm_zone->data;
+
+ vv = ngx_http_get_indexed_variable(r, ctx->index);
+
+ if (vv == NULL || vv->not_found) {
+ continue;
+ }
+
+ len = vv->len;
+
+ if (len == 0) {
+ continue;
+ }
+
+ if (len > 255) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "the value of the \"%V\" variable "
+ "is more than 255 bytes: \"%v\"",
+ &ctx->var, vv);
+ continue;
+ }
+
+ r->main->limit_conn_set = 1;
+
+ hash = ngx_crc32_short(vv->data, len);
+
+ shpool = (ngx_slab_pool_t *) limits[i].shm_zone->shm.addr;
+
+ ngx_shmtx_lock(&shpool->mutex);
+
+ node = ngx_http_limit_conn_lookup(ctx->rbtree, vv, hash);
+
+ if (node == NULL) {
+
+ n = offsetof(ngx_rbtree_node_t, color)
+ + offsetof(ngx_http_limit_conn_node_t, data)
+ + len;
+
+ node = ngx_slab_alloc_locked(shpool, n);
+
+ if (node == NULL) {
+ ngx_shmtx_unlock(&shpool->mutex);
+ ngx_http_limit_conn_cleanup_all(r->pool);
+ return NGX_HTTP_SERVICE_UNAVAILABLE;
+ }
+
+ lc = (ngx_http_limit_conn_node_t *) &node->color;
+
+ node->key = hash;
+ lc->len = (u_char) len;
+ lc->conn = 1;
+ ngx_memcpy(lc->data, vv->data, len);
+
+ ngx_rbtree_insert(ctx->rbtree, node);
+
+ } else {
+
+ lc = (ngx_http_limit_conn_node_t *) &node->color;
+
+ if ((ngx_uint_t) lc->conn >= limits[i].conn) {
+
+ ngx_shmtx_unlock(&shpool->mutex);
+
+ ngx_log_error(lccf->log_level, r->connection->log, 0,
+ "limiting connections by zone \"%V\"",
+ &limits[i].shm_zone->shm.name);
+
+ ngx_http_limit_conn_cleanup_all(r->pool);
+ return NGX_HTTP_SERVICE_UNAVAILABLE;
+ }
+
+ lc->conn++;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "limit zone: %08XD %d", node->key, lc->conn);
+
+ ngx_shmtx_unlock(&shpool->mutex);
+
+ cln = ngx_pool_cleanup_add(r->pool,
+ sizeof(ngx_http_limit_conn_cleanup_t));
+ if (cln == NULL) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ cln->handler = ngx_http_limit_conn_cleanup;
+ lccln = cln->data;
+
+ lccln->shm_zone = limits[i].shm_zone;
+ lccln->node = node;
+ }
+
+ return NGX_DECLINED;
+}
+
+
+static void
+ngx_http_limit_conn_rbtree_insert_value(ngx_rbtree_node_t *temp,
+ ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
+{
+ ngx_rbtree_node_t **p;
+ ngx_http_limit_conn_node_t *lcn, *lcnt;
+
+ for ( ;; ) {
+
+ if (node->key < temp->key) {
+
+ p = &temp->left;
+
+ } else if (node->key > temp->key) {
+
+ p = &temp->right;
+
+ } else { /* node->key == temp->key */
+
+ lcn = (ngx_http_limit_conn_node_t *) &node->color;
+ lcnt = (ngx_http_limit_conn_node_t *) &temp->color;
+
+ p = (ngx_memn2cmp(lcn->data, lcnt->data, lcn->len, lcnt->len) < 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);
+}
+
+
+static ngx_rbtree_node_t *
+ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree, ngx_http_variable_value_t *vv,
+ uint32_t hash)
+{
+ ngx_int_t rc;
+ ngx_rbtree_node_t *node, *sentinel;
+ ngx_http_limit_conn_node_t *lcn;
+
+ node = rbtree->root;
+ sentinel = rbtree->sentinel;
+
+ while (node != sentinel) {
+
+ if (hash < node->key) {
+ node = node->left;
+ continue;
+ }
+
+ if (hash > node->key) {
+ node = node->right;
+ continue;
+ }
+
+ /* hash == node->key */
+
+ lcn = (ngx_http_limit_conn_node_t *) &node->color;
+
+ rc = ngx_memn2cmp(vv->data, lcn->data,
+ (size_t) vv->len, (size_t) lcn->len);
+ if (rc == 0) {
+ return node;
+ }
+
+ node = (rc < 0) ? node->left : node->right;
+ }
+
+ return NULL;
+}
+
+
+static void
+ngx_http_limit_conn_cleanup(void *data)
+{
+ ngx_http_limit_conn_cleanup_t *lccln = data;
+
+ ngx_slab_pool_t *shpool;
+ ngx_rbtree_node_t *node;
+ ngx_http_limit_conn_ctx_t *ctx;
+ ngx_http_limit_conn_node_t *lc;
+
+ ctx = lccln->shm_zone->data;
+ shpool = (ngx_slab_pool_t *) lccln->shm_zone->shm.addr;
+ node = lccln->node;
+ lc = (ngx_http_limit_conn_node_t *) &node->color;
+
+ ngx_shmtx_lock(&shpool->mutex);
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, lccln->shm_zone->shm.log, 0,
+ "limit zone cleanup: %08XD %d", node->key, lc->conn);
+
+ lc->conn--;
+
+ if (lc->conn == 0) {
+ ngx_rbtree_delete(ctx->rbtree, node);
+ ngx_slab_free_locked(shpool, node);
+ }
+
+ ngx_shmtx_unlock(&shpool->mutex);
+}
+
+
+static ngx_inline void
+ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool)
+{
+ ngx_pool_cleanup_t *cln;
+
+ cln = pool->cleanup;
+
+ while (cln && cln->handler == ngx_http_limit_conn_cleanup) {
+ ngx_http_limit_conn_cleanup(cln->data);
+ cln = cln->next;
+ }
+
+ pool->cleanup = cln;
+}
+
+
+static ngx_int_t
+ngx_http_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data)
+{
+ ngx_http_limit_conn_ctx_t *octx = data;
+
+ size_t len;
+ ngx_slab_pool_t *shpool;
+ ngx_rbtree_node_t *sentinel;
+ ngx_http_limit_conn_ctx_t *ctx;
+
+ ctx = shm_zone->data;
+
+ if (octx) {
+ if (ngx_strcmp(ctx->var.data, octx->var.data) != 0) {
+ ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
+ "limit_conn_zone \"%V\" uses the \"%V\" variable "
+ "while previously it used the \"%V\" variable",
+ &shm_zone->shm.name, &ctx->var, &octx->var);
+ return NGX_ERROR;
+ }
+
+ ctx->rbtree = octx->rbtree;
+
+ return NGX_OK;
+ }
+
+ shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
+
+ if (shm_zone->shm.exists) {
+ ctx->rbtree = shpool->data;
+
+ return NGX_OK;
+ }
+
+ ctx->rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t));
+ if (ctx->rbtree == NULL) {
+ return NGX_ERROR;
+ }
+
+ shpool->data = ctx->rbtree;
+
+ sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t));
+ if (sentinel == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_rbtree_init(ctx->rbtree, sentinel,
+ ngx_http_limit_conn_rbtree_insert_value);
+
+ len = sizeof(" in limit_conn_zone \"\"") + shm_zone->shm.name.len;
+
+ shpool->log_ctx = ngx_slab_alloc(shpool, len);
+ if (shpool->log_ctx == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_sprintf(shpool->log_ctx, " in limit_conn_zone \"%V\"%Z",
+ &shm_zone->shm.name);
+
+ return NGX_OK;
+}
+
+
+static void *
+ngx_http_limit_conn_create_conf(ngx_conf_t *cf)
+{
+ ngx_http_limit_conn_conf_t *conf;
+
+ conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_conn_conf_t));
+ if (conf == NULL) {
+ return NULL;
+ }
+
+ /*
+ * set by ngx_pcalloc():
+ *
+ * conf->limits.elts = NULL;
+ */
+
+ conf->log_level = NGX_CONF_UNSET_UINT;
+
+ return conf;
+}
+
+
+static char *
+ngx_http_limit_conn_merge_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+ ngx_http_limit_conn_conf_t *prev = parent;
+ ngx_http_limit_conn_conf_t *conf = child;
+
+ if (conf->limits.elts == NULL) {
+ conf->limits = prev->limits;
+ }
+
+ ngx_conf_merge_uint_value(conf->log_level, prev->log_level, NGX_LOG_ERR);
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ u_char *p;
+ ssize_t size;
+ ngx_str_t *value, name, s;
+ ngx_uint_t i;
+ ngx_shm_zone_t *shm_zone;
+ ngx_http_limit_conn_ctx_t *ctx;
+
+ value = cf->args->elts;
+
+ ctx = NULL;
+ size = 0;
+ name.len = 0;
+
+ for (i = 1; i < cf->args->nelts; i++) {
+
+ if (ngx_strncmp(value[i].data, "zone=", 5) == 0) {
+
+ name.data = value[i].data + 5;
+
+ p = (u_char *) ngx_strchr(name.data, ':');
+
+ if (p == NULL) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid zone size \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ name.len = p - name.data;
+
+ s.data = p + 1;
+ s.len = value[i].data + value[i].len - s.data;
+
+ size = ngx_parse_size(&s);
+
+ if (size == NGX_ERROR) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid zone size \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ if (size < (ssize_t) (8 * ngx_pagesize)) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "zone \"%V\" is too small", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ continue;
+ }
+
+ if (value[i].data[0] == '$') {
+
+ value[i].len--;
+ value[i].data++;
+
+ ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_conn_ctx_t));
+ if (ctx == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ ctx->index = ngx_http_get_variable_index(cf, &value[i]);
+ if (ctx->index == NGX_ERROR) {
+ return NGX_CONF_ERROR;
+ }
+
+ ctx->var = value[i];
+
+ continue;
+ }
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid parameter \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ if (name.len == 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"%V\" must have \"zone\" parameter",
+ &cmd->name);
+ return NGX_CONF_ERROR;
+ }
+
+ if (ctx == NULL) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "no variable is defined for %V \"%V\"",
+ &cmd->name, &name);
+ return NGX_CONF_ERROR;
+ }
+
+ shm_zone = ngx_shared_memory_add(cf, &name, size,
+ &ngx_http_limit_conn_module);
+ if (shm_zone == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (shm_zone->data) {
+ ctx = shm_zone->data;
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "%V \"%V\" is already bound to variable \"%V\"",
+ &cmd->name, &name, &ctx->var);
+ return NGX_CONF_ERROR;
+ }
+
+ shm_zone->init = ngx_http_limit_conn_init_zone;
+ shm_zone->data = ctx;
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_http_limit_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ssize_t n;
+ ngx_str_t *value;
+ ngx_shm_zone_t *shm_zone;
+ ngx_http_limit_conn_ctx_t *ctx;
+
+ ngx_conf_deprecated(cf, &ngx_conf_deprecated_limit_zone, NULL);
+
+ value = cf->args->elts;
+
+ if (value[2].data[0] != '$') {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid variable name \"%V\"", &value[2]);
+ return NGX_CONF_ERROR;
+ }
+
+ value[2].len--;
+ value[2].data++;
+
+ ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_conn_ctx_t));
+ if (ctx == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ ctx->index = ngx_http_get_variable_index(cf, &value[2]);
+ if (ctx->index == NGX_ERROR) {
+ return NGX_CONF_ERROR;
+ }
+
+ ctx->var = value[2];
+
+ n = ngx_parse_size(&value[3]);
+
+ if (n == NGX_ERROR) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid size of limit_zone \"%V\"", &value[3]);
+ return NGX_CONF_ERROR;
+ }
+
+ if (n < (ngx_int_t) (8 * ngx_pagesize)) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "limit_zone \"%V\" is too small", &value[1]);
+ return NGX_CONF_ERROR;
+ }
+
+
+ shm_zone = ngx_shared_memory_add(cf, &value[1], n,
+ &ngx_http_limit_conn_module);
+ if (shm_zone == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (shm_zone->data) {
+ ctx = shm_zone->data;
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "limit_zone \"%V\" is already bound to variable \"%V\"",
+ &value[1], &ctx->var);
+ return NGX_CONF_ERROR;
+ }
+
+ shm_zone->init = ngx_http_limit_conn_init_zone;
+ shm_zone->data = ctx;
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_shm_zone_t *shm_zone;
+ ngx_http_limit_conn_conf_t *lccf = conf;
+ ngx_http_limit_conn_limit_t *limit, *limits;
+
+ ngx_str_t *value;
+ ngx_int_t n;
+ ngx_uint_t i;
+
+ value = cf->args->elts;
+
+ shm_zone = ngx_shared_memory_add(cf, &value[1], 0,
+ &ngx_http_limit_conn_module);
+ if (shm_zone == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ limits = lccf->limits.elts;
+
+ if (limits == NULL) {
+ if (ngx_array_init(&lccf->limits, cf->pool, 1,
+ sizeof(ngx_http_limit_conn_limit_t))
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ for (i = 0; i < lccf->limits.nelts; i++) {
+ if (shm_zone == limits[i].shm_zone) {
+ return "is duplicate";
+ }
+ }
+
+ n = ngx_atoi(value[2].data, value[2].len);
+ if (n <= 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid number of connections \"%V\"", &value[2]);
+ return NGX_CONF_ERROR;
+ }
+
+ if (n > 65535) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "connection limit must be less 65536");
+ return NGX_CONF_ERROR;
+ }
+
+ limit = ngx_array_push(&lccf->limits);
+ limit->conn = n;
+ limit->shm_zone = shm_zone;
+
+ return NGX_CONF_OK;
+}
+
+
+static ngx_int_t
+ngx_http_limit_conn_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_PREACCESS_PHASE].handlers);
+ if (h == NULL) {
+ return NGX_ERROR;
+ }
+
+ *h = ngx_http_limit_conn_handler;
+
+ return NGX_OK;
+}
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 24707ee7f4f..18db7154958 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
@@ -18,6 +18,7 @@ typedef struct {
ngx_msec_t last;
/* integer value, 1 corresponds to 0.001 r/s */
ngx_uint_t excess;
+ ngx_uint_t count;
u_char data[1];
} ngx_http_limit_req_node_t;
@@ -36,6 +37,7 @@ typedef struct {
ngx_uint_t rate;
ngx_int_t index;
ngx_str_t var;
+ ngx_http_limit_req_node_t *node;
} ngx_http_limit_req_ctx_t;
@@ -43,16 +45,23 @@ typedef struct {
ngx_shm_zone_t *shm_zone;
/* integer value, 1 corresponds to 0.001 r/s */
ngx_uint_t burst;
+ ngx_uint_t nodelay; /* unsigned nodelay:1 */
+} ngx_http_limit_req_limit_t;
+
+
+typedef struct {
+ ngx_array_t limits;
ngx_uint_t limit_log_level;
ngx_uint_t delay_log_level;
-
- ngx_uint_t nodelay; /* unsigned nodelay:1 */
} ngx_http_limit_req_conf_t;
static void ngx_http_limit_req_delay(ngx_http_request_t *r);
-static ngx_int_t ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lrcf,
- ngx_uint_t hash, u_char *data, size_t len, ngx_uint_t *ep);
+static ngx_int_t ngx_http_limit_req_lookup(ngx_http_limit_req_limit_t *limit,
+ ngx_uint_t hash, u_char *data, size_t len, ngx_uint_t *ep,
+ ngx_uint_t account);
+static ngx_msec_t ngx_http_limit_req_account(ngx_http_limit_req_limit_t *limits,
+ ngx_uint_t n, ngx_uint_t *ep, ngx_http_limit_req_limit_t **limit);
static void ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx,
ngx_uint_t n);
@@ -136,123 +145,124 @@ ngx_module_t ngx_http_limit_req_module = {
static ngx_int_t
ngx_http_limit_req_handler(ngx_http_request_t *r)
{
- size_t len, n;
- uint32_t hash;
- ngx_int_t rc;
- ngx_uint_t excess;
- ngx_time_t *tp;
- ngx_rbtree_node_t *node;
- ngx_http_variable_value_t *vv;
- ngx_http_limit_req_ctx_t *ctx;
- ngx_http_limit_req_node_t *lr;
- ngx_http_limit_req_conf_t *lrcf;
+ size_t len;
+ uint32_t hash;
+ ngx_int_t rc;
+ ngx_uint_t n, excess;
+ ngx_msec_t delay;
+ ngx_http_variable_value_t *vv;
+ ngx_http_limit_req_ctx_t *ctx;
+ ngx_http_limit_req_conf_t *lrcf;
+ ngx_http_limit_req_limit_t *limit, *limits;
if (r->main->limit_req_set) {
return NGX_DECLINED;
}
lrcf = ngx_http_get_module_loc_conf(r, ngx_http_limit_req_module);
+ limits = lrcf->limits.elts;
- if (lrcf->shm_zone == NULL) {
- return NGX_DECLINED;
- }
+ excess = 0;
- ctx = lrcf->shm_zone->data;
+ rc = NGX_DECLINED;
- vv = ngx_http_get_indexed_variable(r, ctx->index);
+#if (NGX_SUPPRESS_WARN)
+ limit = NULL;
+#endif
- if (vv == NULL || vv->not_found) {
- return NGX_DECLINED;
- }
+ for (n = 0; n < lrcf->limits.nelts; n++) {
- len = vv->len;
+ limit = &limits[n];
- if (len == 0) {
- return NGX_DECLINED;
- }
+ ctx = limit->shm_zone->data;
- if (len > 65535) {
- ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
- "the value of the \"%V\" variable "
- "is more than 65535 bytes: \"%v\"",
- &ctx->var, vv);
- return NGX_DECLINED;
- }
+ vv = ngx_http_get_indexed_variable(r, ctx->index);
- r->main->limit_req_set = 1;
-
- hash = ngx_crc32_short(vv->data, len);
+ if (vv == NULL || vv->not_found) {
+ continue;
+ }
- ngx_shmtx_lock(&ctx->shpool->mutex);
+ len = vv->len;
- ngx_http_limit_req_expire(ctx, 1);
+ if (len == 0) {
+ continue;
+ }
- rc = ngx_http_limit_req_lookup(lrcf, hash, vv->data, len, &excess);
+ if (len > 65535) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "the value of the \"%V\" variable "
+ "is more than 65535 bytes: \"%v\"",
+ &ctx->var, vv);
+ continue;
+ }
- ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "limit_req: %i %ui.%03ui", rc, excess / 1000, excess % 1000);
+ hash = ngx_crc32_short(vv->data, len);
- if (rc == NGX_DECLINED) {
+ ngx_shmtx_lock(&ctx->shpool->mutex);
- n = offsetof(ngx_rbtree_node_t, color)
- + offsetof(ngx_http_limit_req_node_t, data)
- + len;
+ rc = ngx_http_limit_req_lookup(limit, hash, vv->data, len, &excess,
+ (n == lrcf->limits.nelts - 1));
- node = ngx_slab_alloc_locked(ctx->shpool, n);
- if (node == NULL) {
+ ngx_shmtx_unlock(&ctx->shpool->mutex);
- ngx_http_limit_req_expire(ctx, 0);
+ ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "limit_req[%ui]: %i %ui.%03ui",
+ n, rc, excess / 1000, excess % 1000);
- node = ngx_slab_alloc_locked(ctx->shpool, n);
- if (node == NULL) {
- ngx_shmtx_unlock(&ctx->shpool->mutex);
- return NGX_HTTP_SERVICE_UNAVAILABLE;
- }
+ if (rc != NGX_AGAIN) {
+ break;
}
+ }
- lr = (ngx_http_limit_req_node_t *) &node->color;
+ if (rc == NGX_DECLINED) {
+ return NGX_DECLINED;
+ }
- node->key = hash;
- lr->len = (u_char) len;
+ r->main->limit_req_set = 1;
- tp = ngx_timeofday();
- lr->last = (ngx_msec_t) (tp->sec * 1000 + tp->msec);
+ if (rc == NGX_BUSY || rc == NGX_ERROR) {
- lr->excess = 0;
- ngx_memcpy(lr->data, vv->data, len);
+ if (rc == NGX_BUSY) {
+ ngx_log_error(lrcf->limit_log_level, r->connection->log, 0,
+ "limiting requests, excess: %ui.%03ui by zone \"%V\"",
+ excess / 1000, excess % 1000,
+ &limit->shm_zone->shm.name);
+ }
- ngx_rbtree_insert(&ctx->sh->rbtree, node);
+ while (n--) {
+ ctx = limits[n].shm_zone->data;
- ngx_queue_insert_head(&ctx->sh->queue, &lr->queue);
+ if (ctx->node == NULL) {
+ continue;
+ }
- ngx_shmtx_unlock(&ctx->shpool->mutex);
+ ngx_shmtx_lock(&ctx->shpool->mutex);
- return NGX_DECLINED;
- }
+ ctx->node->count--;
- ngx_shmtx_unlock(&ctx->shpool->mutex);
+ ngx_shmtx_unlock(&ctx->shpool->mutex);
- if (rc == NGX_OK) {
- return NGX_DECLINED;
+ ctx->node = NULL;
+ }
+
+ return NGX_HTTP_SERVICE_UNAVAILABLE;
}
- if (rc == NGX_BUSY) {
- ngx_log_error(lrcf->limit_log_level, r->connection->log, 0,
- "limiting requests, excess: %ui.%03ui by zone \"%V\"",
- excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name);
+ /* rc == NGX_AGAIN || rc == NGX_OK */
- return NGX_HTTP_SERVICE_UNAVAILABLE;
+ if (rc == NGX_AGAIN) {
+ excess = 0;
}
- /* rc == NGX_AGAIN */
+ delay = ngx_http_limit_req_account(limits, n, &excess, &limit);
- if (lrcf->nodelay) {
+ if (!delay) {
return NGX_DECLINED;
}
ngx_log_error(lrcf->delay_log_level, r->connection->log, 0,
"delaying request, excess: %ui.%03ui, by zone \"%V\"",
- excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name);
+ excess / 1000, excess % 1000, &limit->shm_zone->shm.name);
if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -260,8 +270,7 @@ ngx_http_limit_req_handler(ngx_http_request_t *r)
r->read_event_handler = ngx_http_test_reading;
r->write_event_handler = ngx_http_limit_req_delay;
- ngx_add_timer(r->connection->write,
- (ngx_msec_t) excess * 1000 / ctx->rate);
+ ngx_add_timer(r->connection->write, delay);
return NGX_AGAIN;
}
@@ -342,9 +351,10 @@ ngx_http_limit_req_rbtree_insert_value(ngx_rbtree_node_t *temp,
static ngx_int_t
-ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lrcf, ngx_uint_t hash,
- u_char *data, size_t len, ngx_uint_t *ep)
+ngx_http_limit_req_lookup(ngx_http_limit_req_limit_t *limit, ngx_uint_t hash,
+ u_char *data, size_t len, ngx_uint_t *ep, ngx_uint_t account)
{
+ size_t size;
ngx_int_t rc, excess;
ngx_time_t *tp;
ngx_msec_t now;
@@ -353,7 +363,10 @@ ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lrcf, ngx_uint_t hash,
ngx_http_limit_req_ctx_t *ctx;
ngx_http_limit_req_node_t *lr;
- ctx = lrcf->shm_zone->data;
+ tp = ngx_timeofday();
+ now = (ngx_msec_t) (tp->sec * 1000 + tp->msec);
+
+ ctx = limit->shm_zone->data;
node = ctx->sh->rbtree.root;
sentinel = ctx->sh->rbtree.sentinel;
@@ -380,9 +393,6 @@ ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lrcf, ngx_uint_t hash,
ngx_queue_remove(&lr->queue);
ngx_queue_insert_head(&ctx->sh->queue, &lr->queue);
- tp = ngx_timeofday();
-
- now = (ngx_msec_t) (tp->sec * 1000 + tp->msec);
ms = (ngx_msec_int_t) (now - lr->last);
excess = lr->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000;
@@ -393,18 +403,21 @@ ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lrcf, ngx_uint_t hash,
*ep = excess;
- if ((ngx_uint_t) excess > lrcf->burst) {
+ if ((ngx_uint_t) excess > limit->burst) {
return NGX_BUSY;
}
- lr->excess = excess;
- lr->last = now;
-
- if (excess) {
- return NGX_AGAIN;
+ if (account) {
+ lr->excess = excess;
+ lr->last = now;
+ return NGX_OK;
}
- return NGX_OK;
+ lr->count++;
+
+ ctx->node = lr;
+
+ return NGX_AGAIN;
}
node = (rc < 0) ? node->left : node->right;
@@ -412,7 +425,115 @@ ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lrcf, ngx_uint_t hash,
*ep = 0;
- return NGX_DECLINED;
+ size = offsetof(ngx_rbtree_node_t, color)
+ + offsetof(ngx_http_limit_req_node_t, data)
+ + len;
+
+ ngx_http_limit_req_expire(ctx, 1);
+
+ node = ngx_slab_alloc_locked(ctx->shpool, size);
+
+ if (node == NULL) {
+ ngx_http_limit_req_expire(ctx, 0);
+
+ node = ngx_slab_alloc_locked(ctx->shpool, size);
+ if (node == NULL) {
+ return NGX_ERROR;
+ }
+ }
+
+ node->key = hash;
+
+ ngx_rbtree_insert(&ctx->sh->rbtree, node);
+
+ lr = (ngx_http_limit_req_node_t *) &node->color;
+
+ ngx_queue_insert_head(&ctx->sh->queue, &lr->queue);
+
+ lr->len = (u_char) len;
+ lr->excess = 0;
+
+ ngx_memcpy(lr->data, data, len);
+
+ if (account) {
+ lr->last = now;
+ lr->count = 0;
+ return NGX_OK;
+ }
+
+ lr->last = 0;
+ lr->count = 1;
+
+ ctx->node = lr;
+
+ return NGX_AGAIN;
+}
+
+
+static ngx_msec_t
+ngx_http_limit_req_account(ngx_http_limit_req_limit_t *limits, ngx_uint_t n,
+ ngx_uint_t *ep, ngx_http_limit_req_limit_t **limit)
+{
+ ngx_int_t excess;
+ ngx_time_t *tp;
+ ngx_msec_t now, delay, max_delay;
+ ngx_msec_int_t ms;
+ ngx_http_limit_req_ctx_t *ctx;
+ ngx_http_limit_req_node_t *lr;
+
+ excess = *ep;
+
+ if (excess == 0 || (*limit)->nodelay) {
+ max_delay = 0;
+
+ } else {
+ ctx = (*limit)->shm_zone->data;
+ max_delay = excess * 1000 / ctx->rate;
+ }
+
+ while (n--) {
+ ctx = limits[n].shm_zone->data;
+ lr = ctx->node;
+
+ if (lr == NULL) {
+ continue;
+ }
+
+ ngx_shmtx_lock(&ctx->shpool->mutex);
+
+ tp = ngx_timeofday();
+
+ now = (ngx_msec_t) (tp->sec * 1000 + tp->msec);
+ ms = (ngx_msec_int_t) (now - lr->last);
+
+ excess = lr->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000;
+
+ if (excess < 0) {
+ excess = 0;
+ }
+
+ lr->last = now;
+ lr->excess = excess;
+ lr->count--;
+
+ ngx_shmtx_unlock(&ctx->shpool->mutex);
+
+ ctx->node = NULL;
+
+ if (limits[n].nodelay) {
+ continue;
+ }
+
+ delay = excess * 1000 / ctx->rate;
+
+ if (delay > max_delay) {
+ max_delay = delay;
+ *ep = excess;
+ *limit = &limits[n];
+ }
+ }
+
+ return max_delay;
}
@@ -447,6 +568,16 @@ ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, ngx_uint_t n)
lr = ngx_queue_data(q, ngx_http_limit_req_node_t, queue);
+ if (lr->count) {
+
+ /*
+ * There is not much sense in looking further,
+ * because we bump nodes on the lookup stage.
+ */
+
+ return;
+ }
+
if (n++ != 0) {
ms = (ngx_msec_int_t) (now - lr->last);
@@ -547,9 +678,7 @@ ngx_http_limit_req_create_conf(ngx_conf_t *cf)
/*
* set by ngx_pcalloc():
*
- * conf->shm_zone = NULL;
- * conf->burst = 0;
- * conf->nodelay = 0;
+ * conf->limits.elts = NULL;
*/
conf->limit_log_level = NGX_CONF_UNSET_UINT;
@@ -564,10 +693,8 @@ ngx_http_limit_req_merge_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_http_limit_req_conf_t *prev = parent;
ngx_http_limit_req_conf_t *conf = child;
- if (conf->shm_zone == NULL) {
- conf->shm_zone = prev->shm_zone;
- conf->burst = prev->burst;
- conf->nodelay = prev->nodelay;
+ if (conf->limits.elts == NULL) {
+ conf->limits = prev->limits;
}
ngx_conf_merge_uint_value(conf->limit_log_level, prev->limit_log_level,
@@ -584,7 +711,8 @@ static char *
ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
u_char *p;
- size_t size, len;
+ size_t len;
+ ssize_t size;
ngx_str_t *value, name, s;
ngx_int_t rate, scale;
ngx_uint_t i;
@@ -607,25 +735,32 @@ ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
p = (u_char *) ngx_strchr(name.data, ':');
- if (p) {
- *p = '\0';
+ if (p == NULL) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid zone size \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
- name.len = p - name.data;
+ name.len = p - name.data;
- p++;
+ s.data = p + 1;
+ s.len = value[i].data + value[i].len - s.data;
- s.len = value[i].data + value[i].len - p;
- s.data = p;
+ size = ngx_parse_size(&s);
- size = ngx_parse_size(&s);
- if (size > 8191) {
- continue;
- }
+ if (size == NGX_ERROR) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid zone size \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
}
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "invalid zone size \"%V\"", &value[i]);
- return NGX_CONF_ERROR;
+ if (size < (ssize_t) (8 * ngx_pagesize)) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "zone \"%V\" is too small", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ continue;
}
if (ngx_strncmp(value[i].data, "rate=", 5) == 0) {
@@ -677,7 +812,7 @@ ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return NGX_CONF_ERROR;
}
- if (name.len == 0 || size == 0) {
+ if (name.len == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"%V\" must have \"zone\" parameter",
&cmd->name);
@@ -686,8 +821,8 @@ ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
if (ctx == NULL) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "no variable is defined for limit_req_zone \"%V\"",
- &cmd->name);
+ "no variable is defined for %V \"%V\"",
+ &cmd->name, &name);
return NGX_CONF_ERROR;
}
@@ -703,8 +838,8 @@ ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ctx = shm_zone->data;
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "limit_req_zone \"%V\" is already bound to variable \"%V\"",
- &value[1], &ctx->var);
+ "%V \"%V\" is already bound to variable \"%V\"",
+ &cmd->name, &name, &ctx->var);
return NGX_CONF_ERROR;
}
@@ -720,17 +855,17 @@ ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_limit_req_conf_t *lrcf = conf;
- ngx_int_t burst;
- ngx_str_t *value, s;
- ngx_uint_t i;
-
- if (lrcf->shm_zone) {
- return "is duplicate";
- }
+ ngx_int_t burst;
+ ngx_str_t *value, s;
+ ngx_uint_t i, nodelay;
+ ngx_shm_zone_t *shm_zone;
+ ngx_http_limit_req_limit_t *limit, *limits;
value = cf->args->elts;
+ shm_zone = NULL;
burst = 0;
+ nodelay = 0;
for (i = 1; i < cf->args->nelts; i++) {
@@ -739,9 +874,9 @@ ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
s.len = value[i].len - 5;
s.data = value[i].data + 5;
- lrcf->shm_zone = ngx_shared_memory_add(cf, &s, 0,
- &ngx_http_limit_req_module);
- if (lrcf->shm_zone == NULL) {
+ shm_zone = ngx_shared_memory_add(cf, &s, 0,
+ &ngx_http_limit_req_module);
+ if (shm_zone == NULL) {
return NGX_CONF_ERROR;
}
@@ -761,7 +896,7 @@ ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}
if (ngx_strncmp(value[i].data, "nodelay", 7) == 0) {
- lrcf->nodelay = 1;
+ nodelay = 1;
continue;
}
@@ -770,21 +905,42 @@ ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return NGX_CONF_ERROR;
}
- if (lrcf->shm_zone == NULL) {
+ if (shm_zone == NULL) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"%V\" must have \"zone\" parameter",
&cmd->name);
return NGX_CONF_ERROR;
}
- if (lrcf->shm_zone->data == NULL) {
+ if (shm_zone->data == NULL) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"unknown limit_req_zone \"%V\"",
- &lrcf->shm_zone->shm.name);
+ &shm_zone->shm.name);
return NGX_CONF_ERROR;
}
- lrcf->burst = burst * 1000;
+ limits = lrcf->limits.elts;
+
+ if (limits == NULL) {
+ if (ngx_array_init(&lrcf->limits, cf->pool, 1,
+ sizeof(ngx_http_limit_req_limit_t))
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ for (i = 0; i < lrcf->limits.nelts; i++) {
+ if (shm_zone == limits[i].shm_zone) {
+ return "is duplicate";
+ }
+ }
+
+ limit = ngx_array_push(&lrcf->limits);
+
+ limit->shm_zone = shm_zone;
+ limit->burst = burst * 1000;
+ limit->nodelay = nodelay;
return NGX_CONF_OK;
}
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_limit_zone_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_limit_zone_module.c
deleted file mode 100644
index 5ebedcd902b..00000000000
--- a/usr.sbin/nginx/src/http/modules/ngx_http_limit_zone_module.c
+++ /dev/null
@@ -1,553 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- * Copyright (C) Nginx, Inc.
- */
-
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-#include <ngx_http.h>
-
-
-typedef struct {
- u_char color;
- u_char len;
- u_short conn;
- u_char data[1];
-} ngx_http_limit_zone_node_t;
-
-
-typedef struct {
- ngx_shm_zone_t *shm_zone;
- ngx_rbtree_node_t *node;
-} ngx_http_limit_zone_cleanup_t;
-
-
-typedef struct {
- ngx_rbtree_t *rbtree;
- ngx_int_t index;
- ngx_str_t var;
-} ngx_http_limit_zone_ctx_t;
-
-
-typedef struct {
- ngx_shm_zone_t *shm_zone;
- ngx_uint_t conn;
- ngx_uint_t log_level;
-} ngx_http_limit_zone_conf_t;
-
-
-static void ngx_http_limit_zone_cleanup(void *data);
-
-static void *ngx_http_limit_zone_create_conf(ngx_conf_t *cf);
-static char *ngx_http_limit_zone_merge_conf(ngx_conf_t *cf, void *parent,
- void *child);
-static char *ngx_http_limit_zone(ngx_conf_t *cf, ngx_command_t *cmd,
- void *conf);
-static char *ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd,
- void *conf);
-static ngx_int_t ngx_http_limit_zone_init(ngx_conf_t *cf);
-
-
-static ngx_conf_enum_t ngx_http_limit_conn_log_levels[] = {
- { ngx_string("info"), NGX_LOG_INFO },
- { ngx_string("notice"), NGX_LOG_NOTICE },
- { ngx_string("warn"), NGX_LOG_WARN },
- { ngx_string("error"), NGX_LOG_ERR },
- { ngx_null_string, 0 }
-};
-
-
-static ngx_command_t ngx_http_limit_zone_commands[] = {
-
- { ngx_string("limit_zone"),
- NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE3,
- ngx_http_limit_zone,
- 0,
- 0,
- NULL },
-
- { ngx_string("limit_conn"),
- NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
- ngx_http_limit_conn,
- NGX_HTTP_LOC_CONF_OFFSET,
- 0,
- NULL },
-
- { ngx_string("limit_conn_log_level"),
- 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_limit_zone_conf_t, log_level),
- &ngx_http_limit_conn_log_levels },
-
- ngx_null_command
-};
-
-
-static ngx_http_module_t ngx_http_limit_zone_module_ctx = {
- NULL, /* preconfiguration */
- ngx_http_limit_zone_init, /* postconfiguration */
-
- NULL, /* create main configuration */
- NULL, /* init main configuration */
-
- NULL, /* create server configuration */
- NULL, /* merge server configuration */
-
- ngx_http_limit_zone_create_conf, /* create location configuration */
- ngx_http_limit_zone_merge_conf /* merge location configuration */
-};
-
-
-ngx_module_t ngx_http_limit_zone_module = {
- NGX_MODULE_V1,
- &ngx_http_limit_zone_module_ctx, /* module context */
- ngx_http_limit_zone_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_limit_zone_handler(ngx_http_request_t *r)
-{
- size_t len, n;
- uint32_t hash;
- ngx_int_t rc;
- ngx_slab_pool_t *shpool;
- ngx_rbtree_node_t *node, *sentinel;
- ngx_pool_cleanup_t *cln;
- ngx_http_variable_value_t *vv;
- ngx_http_limit_zone_ctx_t *ctx;
- ngx_http_limit_zone_node_t *lz;
- ngx_http_limit_zone_conf_t *lzcf;
- ngx_http_limit_zone_cleanup_t *lzcln;
-
- if (r->main->limit_zone_set) {
- return NGX_DECLINED;
- }
-
- lzcf = ngx_http_get_module_loc_conf(r, ngx_http_limit_zone_module);
-
- if (lzcf->shm_zone == NULL) {
- return NGX_DECLINED;
- }
-
- ctx = lzcf->shm_zone->data;
-
- vv = ngx_http_get_indexed_variable(r, ctx->index);
-
- if (vv == NULL || vv->not_found) {
- return NGX_DECLINED;
- }
-
- len = vv->len;
-
- if (len == 0) {
- return NGX_DECLINED;
- }
-
- if (len > 255) {
- ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
- "the value of the \"%V\" variable "
- "is more than 255 bytes: \"%v\"",
- &ctx->var, vv);
- return NGX_DECLINED;
- }
-
- r->main->limit_zone_set = 1;
-
- hash = ngx_crc32_short(vv->data, len);
-
- cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_limit_zone_cleanup_t));
- if (cln == NULL) {
- return NGX_HTTP_INTERNAL_SERVER_ERROR;
- }
-
- shpool = (ngx_slab_pool_t *) lzcf->shm_zone->shm.addr;
-
- ngx_shmtx_lock(&shpool->mutex);
-
- node = ctx->rbtree->root;
- sentinel = ctx->rbtree->sentinel;
-
- while (node != sentinel) {
-
- if (hash < node->key) {
- node = node->left;
- continue;
- }
-
- if (hash > node->key) {
- node = node->right;
- continue;
- }
-
- /* hash == node->key */
-
- lz = (ngx_http_limit_zone_node_t *) &node->color;
-
- rc = ngx_memn2cmp(vv->data, lz->data, len, (size_t) lz->len);
-
- if (rc == 0) {
- if ((ngx_uint_t) lz->conn < lzcf->conn) {
- lz->conn++;
- goto done;
- }
-
- ngx_shmtx_unlock(&shpool->mutex);
-
- ngx_log_error(lzcf->log_level, r->connection->log, 0,
- "limiting connections by zone \"%V\"",
- &lzcf->shm_zone->shm.name);
-
- return NGX_HTTP_SERVICE_UNAVAILABLE;
- }
-
- node = (rc < 0) ? node->left : node->right;
- }
-
- n = offsetof(ngx_rbtree_node_t, color)
- + offsetof(ngx_http_limit_zone_node_t, data)
- + len;
-
- node = ngx_slab_alloc_locked(shpool, n);
- if (node == NULL) {
- ngx_shmtx_unlock(&shpool->mutex);
- return NGX_HTTP_SERVICE_UNAVAILABLE;
- }
-
- lz = (ngx_http_limit_zone_node_t *) &node->color;
-
- node->key = hash;
- lz->len = (u_char) len;
- lz->conn = 1;
- ngx_memcpy(lz->data, vv->data, len);
-
- ngx_rbtree_insert(ctx->rbtree, node);
-
-done:
-
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "limit zone: %08XD %d", node->key, lz->conn);
-
- ngx_shmtx_unlock(&shpool->mutex);
-
- cln->handler = ngx_http_limit_zone_cleanup;
- lzcln = cln->data;
-
- lzcln->shm_zone = lzcf->shm_zone;
- lzcln->node = node;
-
- return NGX_DECLINED;
-}
-
-
-static void
-ngx_http_limit_zone_rbtree_insert_value(ngx_rbtree_node_t *temp,
- ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
-{
- ngx_rbtree_node_t **p;
- ngx_http_limit_zone_node_t *lzn, *lznt;
-
- for ( ;; ) {
-
- if (node->key < temp->key) {
-
- p = &temp->left;
-
- } else if (node->key > temp->key) {
-
- p = &temp->right;
-
- } else { /* node->key == temp->key */
-
- lzn = (ngx_http_limit_zone_node_t *) &node->color;
- lznt = (ngx_http_limit_zone_node_t *) &temp->color;
-
- p = (ngx_memn2cmp(lzn->data, lznt->data, lzn->len, lznt->len) < 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);
-}
-
-
-static void
-ngx_http_limit_zone_cleanup(void *data)
-{
- ngx_http_limit_zone_cleanup_t *lzcln = data;
-
- ngx_slab_pool_t *shpool;
- ngx_rbtree_node_t *node;
- ngx_http_limit_zone_ctx_t *ctx;
- ngx_http_limit_zone_node_t *lz;
-
- ctx = lzcln->shm_zone->data;
- shpool = (ngx_slab_pool_t *) lzcln->shm_zone->shm.addr;
- node = lzcln->node;
- lz = (ngx_http_limit_zone_node_t *) &node->color;
-
- ngx_shmtx_lock(&shpool->mutex);
-
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, lzcln->shm_zone->shm.log, 0,
- "limit zone cleanup: %08XD %d", node->key, lz->conn);
-
- lz->conn--;
-
- if (lz->conn == 0) {
- ngx_rbtree_delete(ctx->rbtree, node);
- ngx_slab_free_locked(shpool, node);
- }
-
- ngx_shmtx_unlock(&shpool->mutex);
-}
-
-
-static ngx_int_t
-ngx_http_limit_zone_init_zone(ngx_shm_zone_t *shm_zone, void *data)
-{
- ngx_http_limit_zone_ctx_t *octx = data;
-
- size_t len;
- ngx_slab_pool_t *shpool;
- ngx_rbtree_node_t *sentinel;
- ngx_http_limit_zone_ctx_t *ctx;
-
- ctx = shm_zone->data;
-
- if (octx) {
- if (ngx_strcmp(ctx->var.data, octx->var.data) != 0) {
- ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
- "limit_zone \"%V\" uses the \"%V\" variable "
- "while previously it used the \"%V\" variable",
- &shm_zone->shm.name, &ctx->var, &octx->var);
- return NGX_ERROR;
- }
-
- ctx->rbtree = octx->rbtree;
-
- return NGX_OK;
- }
-
- shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
-
- if (shm_zone->shm.exists) {
- ctx->rbtree = shpool->data;
-
- return NGX_OK;
- }
-
- ctx->rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t));
- if (ctx->rbtree == NULL) {
- return NGX_ERROR;
- }
-
- shpool->data = ctx->rbtree;
-
- sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t));
- if (sentinel == NULL) {
- return NGX_ERROR;
- }
-
- ngx_rbtree_init(ctx->rbtree, sentinel,
- ngx_http_limit_zone_rbtree_insert_value);
-
- len = sizeof(" in limit_zone \"\"") + shm_zone->shm.name.len;
-
- shpool->log_ctx = ngx_slab_alloc(shpool, len);
- if (shpool->log_ctx == NULL) {
- return NGX_ERROR;
- }
-
- ngx_sprintf(shpool->log_ctx, " in limit_zone \"%V\"%Z",
- &shm_zone->shm.name);
-
- return NGX_OK;
-}
-
-
-static void *
-ngx_http_limit_zone_create_conf(ngx_conf_t *cf)
-{
- ngx_http_limit_zone_conf_t *conf;
-
- conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_zone_conf_t));
- if (conf == NULL) {
- return NULL;
- }
-
- /*
- * set by ngx_pcalloc():
- *
- * conf->shm_zone = NULL;
- * conf->conn = 0;
- */
-
- conf->log_level = NGX_CONF_UNSET_UINT;
-
- return conf;
-}
-
-
-static char *
-ngx_http_limit_zone_merge_conf(ngx_conf_t *cf, void *parent, void *child)
-{
- ngx_http_limit_zone_conf_t *prev = parent;
- ngx_http_limit_zone_conf_t *conf = child;
-
- if (conf->shm_zone == NULL) {
- conf->shm_zone = prev->shm_zone;
- conf->conn = prev->conn;
- }
-
- ngx_conf_merge_uint_value(conf->log_level, prev->log_level, NGX_LOG_ERR);
-
- return NGX_CONF_OK;
-}
-
-
-static char *
-ngx_http_limit_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-{
- ssize_t n;
- ngx_str_t *value;
- ngx_shm_zone_t *shm_zone;
- ngx_http_limit_zone_ctx_t *ctx;
-
- value = cf->args->elts;
-
- if (value[2].data[0] != '$') {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "invalid variable name \"%V\"", &value[2]);
- return NGX_CONF_ERROR;
- }
-
- value[2].len--;
- value[2].data++;
-
- ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_zone_ctx_t));
- if (ctx == NULL) {
- return NGX_CONF_ERROR;
- }
-
- ctx->index = ngx_http_get_variable_index(cf, &value[2]);
- if (ctx->index == NGX_ERROR) {
- return NGX_CONF_ERROR;
- }
-
- ctx->var = value[2];
-
- n = ngx_parse_size(&value[3]);
-
- if (n == NGX_ERROR) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "invalid size of limit_zone \"%V\"", &value[3]);
- return NGX_CONF_ERROR;
- }
-
- if (n < (ngx_int_t) (8 * ngx_pagesize)) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "limit_zone \"%V\" is too small", &value[1]);
- return NGX_CONF_ERROR;
- }
-
-
- shm_zone = ngx_shared_memory_add(cf, &value[1], n,
- &ngx_http_limit_zone_module);
- if (shm_zone == NULL) {
- return NGX_CONF_ERROR;
- }
-
- if (shm_zone->data) {
- ctx = shm_zone->data;
-
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "limit_zone \"%V\" is already bound to variable \"%V\"",
- &value[1], &ctx->var);
- return NGX_CONF_ERROR;
- }
-
- shm_zone->init = ngx_http_limit_zone_init_zone;
- shm_zone->data = ctx;
-
- return NGX_CONF_OK;
-}
-
-
-static char *
-ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-{
- ngx_http_limit_zone_conf_t *lzcf = conf;
-
- ngx_int_t n;
- ngx_str_t *value;
-
- if (lzcf->shm_zone) {
- return "is duplicate";
- }
-
- value = cf->args->elts;
-
- lzcf->shm_zone = ngx_shared_memory_add(cf, &value[1], 0,
- &ngx_http_limit_zone_module);
- if (lzcf->shm_zone == NULL) {
- return NGX_CONF_ERROR;
- }
-
- n = ngx_atoi(value[2].data, value[2].len);
- if (n <= 0) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "invalid number of connections \"%V\"", &value[2]);
- return NGX_CONF_ERROR;
- }
-
- if (n > 65535) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "connection limit must be less 65536");
- return NGX_CONF_ERROR;
- }
-
- lzcf->conn = n;
-
- return NGX_CONF_OK;
-}
-
-
-static ngx_int_t
-ngx_http_limit_zone_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_PREACCESS_PHASE].handlers);
- if (h == NULL) {
- return NGX_ERROR;
- }
-
- *h = ngx_http_limit_zone_handler;
-
- return NGX_OK;
-}
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 b40bdd4e59a..2d412853bd9 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
@@ -80,6 +80,8 @@ static ssize_t ngx_http_log_script_write(ngx_http_request_t *r,
static u_char *ngx_http_log_connection(ngx_http_request_t *r, u_char *buf,
ngx_http_log_op_t *op);
+static u_char *ngx_http_log_connection_requests(ngx_http_request_t *r,
+ u_char *buf, ngx_http_log_op_t *op);
static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf,
ngx_http_log_op_t *op);
static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf,
@@ -193,6 +195,8 @@ static ngx_str_t ngx_http_combined_fmt =
static ngx_http_log_var_t ngx_http_log_vars[] = {
{ ngx_string("connection"), NGX_ATOMIC_T_LEN, ngx_http_log_connection },
+ { ngx_string("connection_requests"), NGX_INT_T_LEN,
+ ngx_http_log_connection_requests },
{ ngx_string("pipe"), 1, ngx_http_log_pipe },
{ ngx_string("time_local"), sizeof("28/Sep/1970:12:00:00 +0600") - 1,
ngx_http_log_time },
@@ -373,6 +377,8 @@ ngx_http_log_script_write(ngx_http_request_t *r, ngx_http_log_script_t *script,
ngx_http_log_loc_conf_t *llcf;
ngx_http_core_loc_conf_t *clcf;
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
if (!r->root_tested) {
/* test root directory existence */
@@ -384,8 +390,6 @@ ngx_http_log_script_write(ngx_http_request_t *r, ngx_http_log_script_t *script,
path.data[root] = '\0';
- clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
ngx_memzero(&of, sizeof(ngx_open_file_info_t));
of.valid = clcf->open_file_cache_valid;
@@ -395,6 +399,11 @@ ngx_http_log_script_write(ngx_http_request_t *r, ngx_http_log_script_t *script,
of.errors = clcf->open_file_cache_errors;
of.events = clcf->open_file_cache_events;
+ if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
+ /* simulate successful logging */
+ return len;
+ }
+
if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
!= NGX_OK)
{
@@ -442,6 +451,11 @@ ngx_http_log_script_write(ngx_http_request_t *r, ngx_http_log_script_t *script,
of.min_uses = llcf->open_file_cache_min_uses;
of.directio = NGX_OPEN_FILE_DIRECTIO_OFF;
+ if (ngx_http_set_disable_symlinks(r, clcf, &log, &of) != NGX_OK) {
+ /* simulate successful logging */
+ return len;
+ }
+
if (ngx_open_cached_file(llcf->open_file_cache, &log, &of, r->pool)
!= NGX_OK)
{
@@ -491,7 +505,15 @@ static u_char *
ngx_http_log_connection(ngx_http_request_t *r, u_char *buf,
ngx_http_log_op_t *op)
{
- return ngx_sprintf(buf, "%ui", r->connection->number);
+ return ngx_sprintf(buf, "%uA", r->connection->number);
+}
+
+
+static u_char *
+ngx_http_log_connection_requests(ngx_http_request_t *r, u_char *buf,
+ ngx_http_log_op_t *op)
+{
+ return ngx_sprintf(buf, "%ui", r->connection->requests);
}
@@ -972,7 +994,7 @@ buffer:
if (buf == NGX_ERROR) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "invalid parameter \"%V\"", &value[3]);
+ "invalid buffer value \"%V\"", &name);
return NGX_CONF_ERROR;
}
@@ -1005,6 +1027,12 @@ ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ngx_uint_t i;
ngx_http_log_fmt_t *fmt;
+ if (cf->cmd_type != NGX_HTTP_MAIN_CONF) {
+ ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+ "the \"log_format\" directive may be used "
+ "only on \"http\" level");
+ }
+
value = cf->args->elts;
fmt = lmcf->formats.elts;
@@ -1243,7 +1271,7 @@ ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
s.data = value[i].data + 9;
inactive = ngx_parse_time(&s, 1);
- if (inactive < 0) {
+ if (inactive == (time_t) NGX_ERROR) {
goto failed;
}
@@ -1266,7 +1294,7 @@ ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
s.data = value[i].data + 6;
valid = ngx_parse_time(&s, 1);
- if (valid < 0) {
+ if (valid == (time_t) NGX_ERROR) {
goto failed;
}
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 604334be77e..5077ded9acb 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
@@ -345,8 +345,8 @@ found:
while (*p && *p++ != CR) { /* void */ }
- r->headers_out.content_length_n = ngx_atoof(len, p - len - 1);
- if (r->headers_out.content_length_n == -1) {
+ u->headers_in.content_length_n = ngx_atoof(len, p - len - 1);
+ 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\" "
"for key \"%V\"",
@@ -367,6 +367,7 @@ found:
u->headers_in.status_n = 404;
u->state->status = 404;
+ u->keepalive = 1;
return NGX_OK;
}
@@ -408,7 +409,7 @@ ngx_http_memcached_filter(void *data, ssize_t bytes)
u = ctx->request->upstream;
b = &u->buffer;
- if (u->length == ctx->rest) {
+ if (u->length == (ssize_t) ctx->rest) {
if (ngx_strncmp(b->last,
ngx_http_memcached_end + NGX_HTTP_MEMCACHED_END - ctx->rest,
@@ -427,6 +428,10 @@ ngx_http_memcached_filter(void *data, ssize_t bytes)
u->length -= bytes;
ctx->rest -= bytes;
+ if (u->length == 0) {
+ u->keepalive = 1;
+ }
+
return NGX_OK;
}
@@ -464,6 +469,13 @@ ngx_http_memcached_filter(void *data, ssize_t bytes)
if (ngx_strncmp(last, ngx_http_memcached_end, b->last - last) != 0) {
ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0,
"memcached sent invalid trailer");
+
+ b->last = last;
+ cl->buf->last = last;
+ u->length = 0;
+ ctx->rest = 0;
+
+ return NGX_OK;
}
ctx->rest -= b->last - last;
@@ -471,6 +483,10 @@ ngx_http_memcached_filter(void *data, ssize_t bytes)
cl->buf->last = last;
u->length = ctx->rest;
+ if (u->length == 0) {
+ u->keepalive = 1;
+ }
+
return NGX_OK;
}
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 92dfbd4116a..433e118a227 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
@@ -442,6 +442,10 @@ ngx_http_mp4_handler(ngx_http_request_t *r)
of.errors = clcf->open_file_cache_errors;
of.events = clcf->open_file_cache_events;
+ if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
!= NGX_OK)
{
@@ -459,6 +463,10 @@ ngx_http_mp4_handler(ngx_http_request_t *r)
break;
case NGX_EACCES:
+#if (NGX_HAVE_OPENAT)
+ case NGX_EMLINK:
+ case NGX_ELOOP:
+#endif
level = NGX_LOG_ERR;
rc = NGX_HTTP_FORBIDDEN;
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 75249b74969..387f77f9b34 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
@@ -10,25 +10,23 @@
#include <ngx_http.h>
-typedef struct ngx_http_proxy_redirect_s ngx_http_proxy_redirect_t;
+typedef struct ngx_http_proxy_rewrite_s ngx_http_proxy_rewrite_t;
-typedef ngx_int_t (*ngx_http_proxy_redirect_pt)(ngx_http_request_t *r,
- ngx_table_elt_t *h, size_t prefix, ngx_http_proxy_redirect_t *pr);
+typedef ngx_int_t (*ngx_http_proxy_rewrite_pt)(ngx_http_request_t *r,
+ ngx_table_elt_t *h, size_t prefix, size_t len,
+ ngx_http_proxy_rewrite_t *pr);
-struct ngx_http_proxy_redirect_s {
- ngx_http_proxy_redirect_pt handler;
- ngx_str_t redirect;
+struct ngx_http_proxy_rewrite_s {
+ ngx_http_proxy_rewrite_pt handler;
union {
- ngx_str_t text;
-
- struct {
- void *lengths;
- void *values;
- } vars;
+ ngx_http_complex_value_t complex;
+#if (NGX_PCRE)
+ ngx_http_regex_t *regex;
+#endif
+ } pattern;
- void *regex;
- } replacement;
+ ngx_http_complex_value_t replacement;
};
@@ -57,6 +55,8 @@ typedef struct {
ngx_array_t *proxy_values;
ngx_array_t *redirects;
+ ngx_array_t *cookie_domains;
+ ngx_array_t *cookie_paths;
ngx_str_t body_source;
@@ -72,6 +72,8 @@ typedef struct {
ngx_flag_t redirect;
+ ngx_uint_t http_version;
+
ngx_uint_t headers_hash_max_size;
ngx_uint_t headers_hash_bucket_size;
} ngx_http_proxy_loc_conf_t;
@@ -81,6 +83,12 @@ typedef struct {
ngx_http_status_t status;
ngx_http_proxy_vars_t vars;
size_t internal_body_length;
+
+ ngx_uint_t state;
+ off_t size;
+ off_t length;
+
+ ngx_uint_t head; /* unsigned head:1 */
} ngx_http_proxy_ctx_t;
@@ -93,6 +101,15 @@ static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r);
static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r);
+static ngx_int_t ngx_http_proxy_input_filter_init(void *data);
+static ngx_int_t ngx_http_proxy_copy_filter(ngx_event_pipe_t *p,
+ ngx_buf_t *buf);
+static ngx_int_t ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p,
+ ngx_buf_t *buf);
+static ngx_int_t ngx_http_proxy_non_buffered_copy_filter(void *data,
+ ssize_t bytes);
+static ngx_int_t ngx_http_proxy_non_buffered_chunked_filter(void *data,
+ ssize_t bytes);
static void ngx_http_proxy_abort_request(ngx_http_request_t *r);
static void ngx_http_proxy_finalize_request(ngx_http_request_t *r,
ngx_int_t rc);
@@ -109,6 +126,12 @@ static ngx_int_t
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r,
ngx_table_elt_t *h, size_t prefix);
+static ngx_int_t ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r,
+ ngx_table_elt_t *h);
+static ngx_int_t ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r,
+ ngx_table_elt_t *h, u_char *value, ngx_array_t *rewrites);
+static ngx_int_t ngx_http_proxy_rewrite(ngx_http_request_t *r,
+ ngx_table_elt_t *h, size_t prefix, size_t len, ngx_str_t *replacement);
static ngx_int_t ngx_http_proxy_add_variables(ngx_conf_t *cf);
static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf);
@@ -121,6 +144,10 @@ static char *ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
+static char *ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+static char *ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
static char *ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
#if (NGX_HTTP_CACHE)
@@ -132,6 +159,9 @@ static char *ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data);
+static ngx_int_t ngx_http_proxy_rewrite_regex(ngx_conf_t *cf,
+ ngx_http_proxy_rewrite_t *pr, ngx_str_t *regex, ngx_uint_t caseless);
+
#if (NGX_HTTP_SSL)
static ngx_int_t ngx_http_proxy_set_ssl(ngx_conf_t *cf,
ngx_http_proxy_loc_conf_t *plcf);
@@ -158,6 +188,13 @@ static ngx_conf_bitmask_t ngx_http_proxy_next_upstream_masks[] = {
};
+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 },
+ { ngx_null_string, 0 }
+};
+
+
ngx_module_t ngx_http_proxy_module;
@@ -177,6 +214,20 @@ static ngx_command_t ngx_http_proxy_commands[] = {
0,
NULL },
+ { ngx_string("proxy_cookie_domain"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
+ ngx_http_proxy_cookie_domain,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ 0,
+ NULL },
+
+ { ngx_string("proxy_cookie_path"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
+ ngx_http_proxy_cookie_path,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ 0,
+ NULL },
+
{ ngx_string("proxy_store"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_http_proxy_store,
@@ -382,6 +433,20 @@ static ngx_command_t ngx_http_proxy_commands[] = {
offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_methods),
&ngx_http_upstream_cache_method_mask },
+ { ngx_string("proxy_cache_lock"),
+ 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_lock),
+ NULL },
+
+ { ngx_string("proxy_cache_lock_timeout"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_msec_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock_timeout),
+ NULL },
+
#endif
{ ngx_string("proxy_temp_path"),
@@ -433,6 +498,13 @@ static ngx_command_t ngx_http_proxy_commands[] = {
offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_headers),
&ngx_http_upstream_ignore_headers_masks },
+ { ngx_string("proxy_http_version"),
+ 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_proxy_loc_conf_t, http_version),
+ &ngx_http_proxy_http_version },
+
#if (NGX_HTTP_SSL)
{ ngx_string("proxy_ssl_session_reuse"),
@@ -480,6 +552,7 @@ ngx_module_t ngx_http_proxy_module = {
static char ngx_http_proxy_version[] = " HTTP/1.0" CRLF;
+static char ngx_http_proxy_version_11[] = " HTTP/1.1" CRLF;
static ngx_keyval_t ngx_http_proxy_headers[] = {
@@ -487,6 +560,7 @@ static ngx_keyval_t ngx_http_proxy_headers[] = {
{ ngx_string("Connection"), ngx_string("close") },
{ ngx_string("Keep-Alive"), ngx_string("") },
{ ngx_string("Expect"), ngx_string("") },
+ { ngx_string("Upgrade"), ngx_string("") },
{ ngx_null_string, ngx_null_string }
};
@@ -511,6 +585,7 @@ static ngx_keyval_t ngx_http_proxy_cache_headers[] = {
{ ngx_string("Connection"), ngx_string("close") },
{ 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-Unmodified-Since"), ngx_string("") },
{ ngx_string("If-None-Match"), ngx_string("") },
@@ -604,6 +679,10 @@ ngx_http_proxy_handler(ngx_http_request_t *r)
u->rewrite_redirect = ngx_http_proxy_rewrite_redirect;
}
+ if (plcf->cookie_domains || plcf->cookie_paths) {
+ u->rewrite_cookie = ngx_http_proxy_rewrite_cookie;
+ }
+
u->buffering = plcf->upstream.buffering;
u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
@@ -611,7 +690,12 @@ ngx_http_proxy_handler(ngx_http_request_t *r)
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
- u->pipe->input_filter = ngx_event_pipe_copy_input_filter;
+ u->pipe->input_filter = ngx_http_proxy_copy_filter;
+ u->pipe->input_ctx = r;
+
+ u->input_filter_init = ngx_http_proxy_input_filter_init;
+ u->input_filter = ngx_http_proxy_non_buffered_copy_filter;
+ u->input_filter_ctx = r;
u->accel = 1;
@@ -701,9 +785,6 @@ ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx,
url.uri.len++;
url.uri.data = p - 1;
}
-
- } else {
- url.uri = r->unparsed_uri;
}
ctx->vars.key_start = u->schema;
@@ -771,7 +852,7 @@ ngx_http_proxy_create_key(ngx_http_request_t *r)
return NGX_ERROR;
}
- if (plcf->proxy_lengths) {
+ if (plcf->proxy_lengths && ctx->vars.uri.len) {
*key = ctx->vars.uri;
u->uri = ctx->vars.uri;
@@ -867,15 +948,21 @@ ngx_http_proxy_create_request(ngx_http_request_t *r)
method.len++;
}
+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+
+ if (method.len == 5
+ && ngx_strncasecmp(method.data, (u_char *) "HEAD ", 5) == 0)
+ {
+ ctx->head = 1;
+ }
+
len = method.len + sizeof(ngx_http_proxy_version) - 1 + sizeof(CRLF) - 1;
escape = 0;
loc_len = 0;
unparsed_uri = 0;
- ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
-
- if (plcf->proxy_lengths) {
+ if (plcf->proxy_lengths && ctx->vars.uri.len) {
uri_len = ctx->vars.uri.len;
} else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
@@ -981,7 +1068,7 @@ ngx_http_proxy_create_request(ngx_http_request_t *r)
u->uri.data = b->last;
- if (plcf->proxy_lengths) {
+ if (plcf->proxy_lengths && ctx->vars.uri.len) {
b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
} else if (unparsed_uri) {
@@ -1010,8 +1097,14 @@ ngx_http_proxy_create_request(ngx_http_request_t *r)
u->uri.len = b->last - u->uri.data;
- b->last = ngx_cpymem(b->last, ngx_http_proxy_version,
- sizeof(ngx_http_proxy_version) - 1);
+ if (plcf->http_version == NGX_HTTP_VERSION_11) {
+ b->last = ngx_cpymem(b->last, ngx_http_proxy_version_11,
+ sizeof(ngx_http_proxy_version_11) - 1);
+
+ } else {
+ b->last = ngx_cpymem(b->last, ngx_http_proxy_version,
+ sizeof(ngx_http_proxy_version) - 1);
+ }
ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
@@ -1159,8 +1252,11 @@ ngx_http_proxy_reinit_request(ngx_http_request_t *r)
ctx->status.count = 0;
ctx->status.start = NULL;
ctx->status.end = NULL;
+ ctx->state = 0;
r->upstream->process_header = ngx_http_proxy_process_status_line;
+ r->upstream->pipe->input_filter = ngx_http_proxy_copy_filter;
+ r->upstream->input_filter = ngx_http_proxy_non_buffered_copy_filter;
r->state = 0;
return NGX_OK;
@@ -1211,6 +1307,7 @@ ngx_http_proxy_process_status_line(ngx_http_request_t *r)
r->http_version = NGX_HTTP_VERSION_9;
u->state->status = NGX_HTTP_OK;
+ u->headers_in.connection_close = 1;
return NGX_OK;
}
@@ -1235,6 +1332,10 @@ ngx_http_proxy_process_status_line(ngx_http_request_t *r)
"http proxy status %ui \"%V\"",
u->headers_in.status_n, &u->headers_in.status_line);
+ if (ctx->status.http_version < NGX_HTTP_VERSION_11) {
+ u->headers_in.connection_close = 1;
+ }
+
u->process_header = ngx_http_proxy_process_header;
return ngx_http_proxy_process_header(r);
@@ -1246,6 +1347,8 @@ ngx_http_proxy_process_header(ngx_http_request_t *r)
{
ngx_int_t rc;
ngx_table_elt_t *h;
+ ngx_http_upstream_t *u;
+ ngx_http_proxy_ctx_t *ctx;
ngx_http_upstream_header_t *hh;
ngx_http_upstream_main_conf_t *umcf;
@@ -1343,6 +1446,30 @@ ngx_http_proxy_process_header(ngx_http_request_t *r)
h->lowcase_key = (u_char *) "date";
}
+ /* clear content length if response is chunked */
+
+ u = r->upstream;
+
+ if (u->headers_in.chunked) {
+ u->headers_in.content_length_n = -1;
+ }
+
+ /*
+ * set u->keepalive if response has no body; this allows to keep
+ * connections alive in case of r->header_only or X-Accel-Redirect
+ */
+
+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+
+ if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
+ || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
+ || ctx->head
+ || (!u->headers_in.chunked
+ && u->headers_in.content_length_n == 0))
+ {
+ u->keepalive = !u->headers_in.connection_close;
+ }
+
return NGX_OK;
}
@@ -1360,6 +1487,709 @@ ngx_http_proxy_process_header(ngx_http_request_t *r)
}
+static ngx_int_t
+ngx_http_proxy_input_filter_init(void *data)
+{
+ ngx_http_request_t *r = data;
+ ngx_http_upstream_t *u;
+ ngx_http_proxy_ctx_t *ctx;
+
+ u = r->upstream;
+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+
+ if (ctx == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http proxy filter init s:%d h:%d c:%d l:%O",
+ u->headers_in.status_n, ctx->head, u->headers_in.chunked,
+ u->headers_in.content_length_n);
+
+ /* as per RFC2616, 4.4 Message Length */
+
+ if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
+ || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
+ || ctx->head)
+ {
+ /* 1xx, 204, and 304 and replies to HEAD requests */
+ /* no 1xx since we don't send Expect and Upgrade */
+
+ u->pipe->length = 0;
+ u->length = 0;
+ u->keepalive = !u->headers_in.connection_close;
+
+ } else if (u->headers_in.chunked) {
+ /* chunked */
+
+ u->pipe->input_filter = ngx_http_proxy_chunked_filter;
+ u->pipe->length = 3; /* "0" LF LF */
+
+ u->input_filter = ngx_http_proxy_non_buffered_chunked_filter;
+ u->length = -1;
+
+ } else if (u->headers_in.content_length_n == 0) {
+ /* empty body: special case as filter won't be called */
+
+ u->pipe->length = 0;
+ u->length = 0;
+ u->keepalive = !u->headers_in.connection_close;
+
+ } else {
+ /* content length or connection close */
+
+ u->pipe->length = u->headers_in.content_length_n;
+ u->length = u->headers_in.content_length_n;
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
+{
+ ngx_buf_t *b;
+ ngx_chain_t *cl;
+ ngx_http_request_t *r;
+
+ if (buf->pos == buf->last) {
+ 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;
+ }
+ }
+
+ ngx_memcpy(b, buf, sizeof(ngx_buf_t));
+ b->shadow = buf;
+ b->tag = p->tag;
+ b->last_shadow = 1;
+ 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) {
+ *p->last_in = cl;
+ } else {
+ p->in = cl;
+ }
+ p->last_in = &cl->next;
+
+ if (p->length == -1) {
+ return NGX_OK;
+ }
+
+ p->length -= b->last - b->pos;
+
+ if (p->length == 0) {
+ r = p->input_ctx;
+ p->upstream_done = 1;
+ r->upstream->keepalive = !r->upstream->headers_in.connection_close;
+
+ } else if (p->length < 0) {
+ r = p->input_ctx;
+ p->upstream_done = 1;
+
+ ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
+ "upstream sent too much data");
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_inline ngx_int_t
+ngx_http_proxy_parse_chunked(ngx_http_request_t *r, ngx_buf_t *buf)
+{
+ u_char *pos, ch, c;
+ ngx_int_t rc;
+ ngx_http_proxy_ctx_t *ctx;
+ enum {
+ sw_chunk_start = 0,
+ sw_chunk_size,
+ sw_chunk_extension,
+ sw_chunk_extension_almost_done,
+ sw_chunk_data,
+ sw_after_data,
+ sw_after_data_almost_done,
+ sw_last_chunk_extension,
+ sw_last_chunk_extension_almost_done,
+ sw_trailer,
+ sw_trailer_almost_done,
+ sw_trailer_header,
+ sw_trailer_header_almost_done
+ } state;
+
+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+
+ if (ctx == NULL) {
+ return NGX_ERROR;
+ }
+
+ state = ctx->state;
+
+ if (state == sw_chunk_data && ctx->size == 0) {
+ state = sw_after_data;
+ }
+
+ rc = NGX_AGAIN;
+
+ for (pos = buf->pos; pos < buf->last; pos++) {
+
+ ch = *pos;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http proxy chunked byte: %02Xd s:%d", ch, state);
+
+ switch (state) {
+
+ case sw_chunk_start:
+ if (ch >= '0' && ch <= '9') {
+ state = sw_chunk_size;
+ ctx->size = ch - '0';
+ break;
+ }
+
+ c = (u_char) (ch | 0x20);
+
+ if (c >= 'a' && c <= 'f') {
+ state = sw_chunk_size;
+ ctx->size = c - 'a' + 10;
+ break;
+ }
+
+ goto invalid;
+
+ case sw_chunk_size:
+ if (ch >= '0' && ch <= '9') {
+ ctx->size = ctx->size * 16 + (ch - '0');
+ break;
+ }
+
+ c = (u_char) (ch | 0x20);
+
+ if (c >= 'a' && c <= 'f') {
+ ctx->size = ctx->size * 16 + (c - 'a' + 10);
+ break;
+ }
+
+ if (ctx->size == 0) {
+
+ switch (ch) {
+ case CR:
+ state = sw_last_chunk_extension_almost_done;
+ break;
+ case LF:
+ state = sw_trailer;
+ break;
+ case ';':
+ case ' ':
+ case '\t':
+ state = sw_last_chunk_extension;
+ break;
+ default:
+ goto invalid;
+ }
+
+ break;
+ }
+
+ switch (ch) {
+ case CR:
+ state = sw_chunk_extension_almost_done;
+ break;
+ case LF:
+ state = sw_chunk_data;
+ break;
+ case ';':
+ case ' ':
+ case '\t':
+ state = sw_chunk_extension;
+ break;
+ default:
+ goto invalid;
+ }
+
+ break;
+
+ case sw_chunk_extension:
+ switch (ch) {
+ case CR:
+ state = sw_chunk_extension_almost_done;
+ break;
+ case LF:
+ state = sw_chunk_data;
+ }
+ break;
+
+ case sw_chunk_extension_almost_done:
+ if (ch == LF) {
+ state = sw_chunk_data;
+ break;
+ }
+ goto invalid;
+
+ case sw_chunk_data:
+ rc = NGX_OK;
+ goto data;
+
+ case sw_after_data:
+ switch (ch) {
+ case CR:
+ state = sw_after_data_almost_done;
+ break;
+ case LF:
+ state = sw_chunk_start;
+ }
+ break;
+
+ case sw_after_data_almost_done:
+ if (ch == LF) {
+ state = sw_chunk_start;
+ break;
+ }
+ goto invalid;
+
+ case sw_last_chunk_extension:
+ switch (ch) {
+ case CR:
+ state = sw_last_chunk_extension_almost_done;
+ break;
+ case LF:
+ state = sw_trailer;
+ }
+ break;
+
+ case sw_last_chunk_extension_almost_done:
+ if (ch == LF) {
+ state = sw_trailer;
+ break;
+ }
+ goto invalid;
+
+ case sw_trailer:
+ switch (ch) {
+ case CR:
+ state = sw_trailer_almost_done;
+ break;
+ case LF:
+ goto done;
+ default:
+ state = sw_trailer_header;
+ }
+ break;
+
+ case sw_trailer_almost_done:
+ if (ch == LF) {
+ goto done;
+ }
+ goto invalid;
+
+ case sw_trailer_header:
+ switch (ch) {
+ case CR:
+ state = sw_trailer_header_almost_done;
+ break;
+ case LF:
+ state = sw_trailer;
+ }
+ break;
+
+ case sw_trailer_header_almost_done:
+ if (ch == LF) {
+ state = sw_trailer;
+ break;
+ }
+ goto invalid;
+
+ }
+ }
+
+data:
+
+ ctx->state = state;
+ buf->pos = pos;
+
+ switch (state) {
+
+ case sw_chunk_start:
+ 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);
+ break;
+ case sw_chunk_extension:
+ case sw_chunk_extension_almost_done:
+ ctx->length = 1 /* LF */ + ctx->size + 4 /* LF "0" LF LF */;
+ break;
+ case sw_chunk_data:
+ ctx->length = ctx->size + 4 /* LF "0" LF LF */;
+ break;
+ case sw_after_data:
+ case sw_after_data_almost_done:
+ ctx->length = 4 /* LF "0" LF LF */;
+ break;
+ case sw_last_chunk_extension:
+ case sw_last_chunk_extension_almost_done:
+ ctx->length = 2 /* LF LF */;
+ break;
+ case sw_trailer:
+ case sw_trailer_almost_done:
+ ctx->length = 1 /* LF */;
+ break;
+ case sw_trailer_header:
+ case sw_trailer_header_almost_done:
+ ctx->length = 2 /* LF LF */;
+ break;
+
+ }
+
+ return rc;
+
+done:
+
+ return NGX_DONE;
+
+invalid:
+
+ return NGX_ERROR;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
+{
+ ngx_int_t rc;
+ ngx_buf_t *b, **prev;
+ ngx_chain_t *cl;
+ ngx_http_request_t *r;
+ ngx_http_proxy_ctx_t *ctx;
+
+ if (buf->pos == buf->last) {
+ return NGX_OK;
+ }
+
+ r = p->input_ctx;
+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+
+ if (ctx == NULL) {
+ return NGX_ERROR;
+ }
+
+ b = NULL;
+ prev = &buf->shadow;
+
+ for ( ;; ) {
+
+ rc = ngx_http_proxy_parse_chunked(r, buf);
+
+ if (rc == NGX_OK) {
+
+ /* 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;
+ }
+ }
+
+ ngx_memzero(b, sizeof(ngx_buf_t));
+
+ b->pos = buf->pos;
+ b->start = buf->start;
+ b->end = buf->end;
+ b->tag = p->tag;
+ b->temporary = 1;
+ b->recycled = 1;
+
+ *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 {
+ p->in = cl;
+ }
+ p->last_in = &cl->next;
+
+ /* STUB */ b->num = buf->num;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
+ "input buf #%d %p", b->num, b->pos);
+
+ if (buf->last - buf->pos >= ctx->size) {
+
+ buf->pos += ctx->size;
+ b->last = buf->pos;
+ ctx->size = 0;
+
+ continue;
+ }
+
+ ctx->size -= buf->last - buf->pos;
+ buf->pos = buf->last;
+ b->last = buf->last;
+
+ continue;
+ }
+
+ if (rc == NGX_DONE) {
+
+ /* a whole response has been parsed successfully */
+
+ p->upstream_done = 1;
+ r->upstream->keepalive = !r->upstream->headers_in.connection_close;
+
+ break;
+ }
+
+ if (rc == NGX_AGAIN) {
+
+ /* set p->length, minimal amount of data we want to see */
+
+ p->length = ctx->length;
+
+ break;
+ }
+
+ /* invalid response */
+
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "upstream sent invalid chunked response");
+
+ return NGX_ERROR;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http proxy chunked state %d, length %d",
+ ctx->state, p->length);
+
+ if (b) {
+ b->shadow = buf;
+ b->last_shadow = 1;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
+ "input buf %p %z", b->pos, b->last - b->pos);
+
+ return NGX_OK;
+ }
+
+ /* there is no data record in the buf, add it to free chain */
+
+ if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_non_buffered_copy_filter(void *data, ssize_t bytes)
+{
+ ngx_http_request_t *r = data;
+
+ ngx_buf_t *b;
+ ngx_chain_t *cl, **ll;
+ ngx_http_upstream_t *u;
+
+ u = r->upstream;
+
+ for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
+ ll = &cl->next;
+ }
+
+ cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
+ if (cl == NULL) {
+ return NGX_ERROR;
+ }
+
+ *ll = cl;
+
+ cl->buf->flush = 1;
+ cl->buf->memory = 1;
+
+ b = &u->buffer;
+
+ cl->buf->pos = b->last;
+ b->last += bytes;
+ cl->buf->last = b->last;
+ cl->buf->tag = u->output.tag;
+
+ if (u->length == -1) {
+ return NGX_OK;
+ }
+
+ u->length -= bytes;
+
+ if (u->length == 0) {
+ u->keepalive = !u->headers_in.connection_close;
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes)
+{
+ ngx_http_request_t *r = data;
+
+ ngx_int_t rc;
+ ngx_buf_t *b, *buf;
+ ngx_chain_t *cl, **ll;
+ ngx_http_upstream_t *u;
+ ngx_http_proxy_ctx_t *ctx;
+
+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+
+ if (ctx == NULL) {
+ return NGX_ERROR;
+ }
+
+ 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;
+ }
+
+ for ( ;; ) {
+
+ rc = ngx_http_proxy_parse_chunked(r, buf);
+
+ if (rc == NGX_OK) {
+
+ /* a chunk has been parsed successfully */
+
+ 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 = buf->pos;
+ b->tag = u->output.tag;
+
+ if (buf->last - buf->pos >= ctx->size) {
+ buf->pos += ctx->size;
+ b->last = buf->pos;
+ ctx->size = 0;
+
+ } else {
+ ctx->size -= buf->last - buf->pos;
+ buf->pos = buf->last;
+ b->last = buf->last;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http proxy out buf %p %z",
+ b->pos, b->last - b->pos);
+
+ continue;
+ }
+
+ if (rc == NGX_DONE) {
+
+ /* a whole response has been parsed successfully */
+
+ u->keepalive = !u->headers_in.connection_close;
+ u->length = 0;
+
+ break;
+ }
+
+ if (rc == NGX_AGAIN) {
+ break;
+ }
+
+ /* invalid response */
+
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "upstream sent invalid chunked response");
+
+ return NGX_ERROR;
+ }
+
+ /* 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 proxy 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 void
ngx_http_proxy_abort_request(ngx_http_request_t *r)
{
@@ -1496,10 +2326,11 @@ static ngx_int_t
ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h,
size_t prefix)
{
+ size_t len;
ngx_int_t rc;
ngx_uint_t i;
+ ngx_http_proxy_rewrite_t *pr;
ngx_http_proxy_loc_conf_t *plcf;
- ngx_http_proxy_redirect_t *pr;
plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
@@ -1509,8 +2340,10 @@ ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h,
return NGX_DECLINED;
}
+ len = h->value.len - prefix;
+
for (i = 0; i < plcf->redirects->nelts; i++) {
- rc = pr[i].handler(r, h, prefix, &pr[i]);
+ rc = pr[i].handler(r, h, prefix, len, &pr[i]);
if (rc != NGX_DECLINED) {
return rc;
@@ -1522,91 +2355,209 @@ ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h,
static ngx_int_t
-ngx_http_proxy_rewrite_redirect_text(ngx_http_request_t *r, ngx_table_elt_t *h,
- size_t prefix, ngx_http_proxy_redirect_t *pr)
+ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, ngx_table_elt_t *h)
{
- size_t len;
- u_char *data, *p;
+ size_t prefix;
+ u_char *p;
+ ngx_int_t rc, rv;
+ ngx_http_proxy_loc_conf_t *plcf;
- if (pr->redirect.len > h->value.len - prefix
- || ngx_rstrncmp(h->value.data + prefix, pr->redirect.data,
- pr->redirect.len) != 0)
- {
+ p = (u_char *) ngx_strchr(h->value.data, ';');
+ if (p == NULL) {
return NGX_DECLINED;
}
- len = pr->replacement.text.len + h->value.len - pr->redirect.len;
+ prefix = p + 1 - h->value.data;
- data = ngx_pnalloc(r->pool, len);
- if (data == NULL) {
- return NGX_ERROR;
+ rv = NGX_DECLINED;
+
+ plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
+
+ if (plcf->cookie_domains) {
+ p = ngx_strcasestrn(h->value.data + prefix, "domain=", 7 - 1);
+
+ if (p) {
+ rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 7,
+ plcf->cookie_domains);
+ if (rc == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+
+ if (rc != NGX_DECLINED) {
+ rv = rc;
+ }
+ }
}
- p = ngx_copy(data, h->value.data, prefix);
+ if (plcf->cookie_paths) {
+ p = ngx_strcasestrn(h->value.data + prefix, "path=", 5 - 1);
+
+ if (p) {
+ rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 5,
+ plcf->cookie_paths);
+ if (rc == NGX_ERROR) {
+ return NGX_ERROR;
+ }
- if (pr->replacement.text.len) {
- p = ngx_copy(p, pr->replacement.text.data, pr->replacement.text.len);
+ if (rc != NGX_DECLINED) {
+ rv = rc;
+ }
+ }
}
- ngx_memcpy(p, h->value.data + prefix + pr->redirect.len,
- h->value.len - pr->redirect.len - prefix);
+ return rv;
+}
- h->value.len = len;
- h->value.data = data;
- return NGX_OK;
+static ngx_int_t
+ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, ngx_table_elt_t *h,
+ u_char *value, ngx_array_t *rewrites)
+{
+ size_t len, prefix;
+ u_char *p;
+ ngx_int_t rc;
+ ngx_uint_t i;
+ ngx_http_proxy_rewrite_t *pr;
+
+ prefix = value - h->value.data;
+
+ p = (u_char *) ngx_strchr(value, ';');
+
+ len = p ? (size_t) (p - value) : (h->value.len - prefix);
+
+ pr = rewrites->elts;
+
+ for (i = 0; i < rewrites->nelts; i++) {
+ rc = pr[i].handler(r, h, prefix, len, &pr[i]);
+
+ if (rc != NGX_DECLINED) {
+ return rc;
+ }
+ }
+
+ return NGX_DECLINED;
}
static ngx_int_t
-ngx_http_proxy_rewrite_redirect_vars(ngx_http_request_t *r, ngx_table_elt_t *h,
- size_t prefix, ngx_http_proxy_redirect_t *pr)
+ngx_http_proxy_rewrite_complex_handler(ngx_http_request_t *r,
+ ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
{
- size_t len;
- u_char *data, *p;
- ngx_http_script_code_pt code;
- ngx_http_script_engine_t e;
- ngx_http_script_len_code_pt lcode;
+ ngx_str_t pattern, replacement;
- if (pr->redirect.len > h->value.len - prefix
- || ngx_rstrncmp(h->value.data + prefix, pr->redirect.data,
- pr->redirect.len) != 0)
+ if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ if (pattern.len > len
+ || ngx_rstrncmp(h->value.data + prefix, pattern.data,
+ pattern.len) != 0)
{
return NGX_DECLINED;
}
- ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
+ if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
+ return NGX_ERROR;
+ }
- e.ip = pr->replacement.vars.lengths;
- e.request = r;
+ return ngx_http_proxy_rewrite(r, h, prefix, pattern.len, &replacement);
+}
+
+
+#if (NGX_PCRE)
+
+static ngx_int_t
+ngx_http_proxy_rewrite_regex_handler(ngx_http_request_t *r, ngx_table_elt_t *h,
+ size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
+{
+ ngx_str_t pattern, replacement;
+
+ pattern.len = len;
+ pattern.data = h->value.data + prefix;
- len = h->value.len - pr->redirect.len;
+ if (ngx_http_regex_exec(r, pr->pattern.regex, &pattern) != NGX_OK) {
+ return NGX_DECLINED;
+ }
+
+ if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
+ return NGX_ERROR;
+ }
- while (*(uintptr_t *) e.ip) {
- lcode = *(ngx_http_script_len_code_pt *) e.ip;
- len += lcode(&e);
+ if (prefix == 0 && h->value.len == len) {
+ h->value = replacement;
+ return NGX_OK;
}
- data = ngx_pnalloc(r->pool, len);
- if (data == NULL) {
+ return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement);
+}
+
+#endif
+
+
+static ngx_int_t
+ngx_http_proxy_rewrite_domain_handler(ngx_http_request_t *r,
+ ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
+{
+ u_char *p;
+ ngx_str_t pattern, replacement;
+
+ if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) {
return NGX_ERROR;
}
- p = ngx_copy(data, h->value.data, prefix);
+ p = h->value.data + prefix;
+
+ if (p[0] == '.') {
+ p++;
+ prefix++;
+ len--;
+ }
- e.ip = pr->replacement.vars.values;
- e.pos = p;
+ if (pattern.len != len || ngx_rstrncasecmp(pattern.data, p, len) != 0) {
+ return NGX_DECLINED;
+ }
- while (*(uintptr_t *) e.ip) {
- code = *(ngx_http_script_code_pt *) e.ip;
- code(&e);
+ if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
+ return NGX_ERROR;
}
- ngx_memcpy(e.pos, h->value.data + prefix + pr->redirect.len,
- h->value.len - pr->redirect.len - prefix);
+ return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement);
+}
+
+
+static ngx_int_t
+ngx_http_proxy_rewrite(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix,
+ size_t len, ngx_str_t *replacement)
+{
+ u_char *p, *data;
+ size_t new_len;
+
+ new_len = replacement->len + h->value.len - len;
+
+ if (replacement->len > len) {
+
+ data = ngx_pnalloc(r->pool, new_len);
+ if (data == NULL) {
+ return NGX_ERROR;
+ }
+
+ p = ngx_copy(data, h->value.data, prefix);
+ p = ngx_copy(p, replacement->data, replacement->len);
+
+ ngx_memcpy(p, h->value.data + prefix + len,
+ h->value.len - len - prefix);
+
+ h->value.data = data;
+
+ } else {
+ p = ngx_copy(h->value.data + prefix, replacement->data,
+ replacement->len);
+
+ ngx_memmove(p, h->value.data + prefix + len,
+ h->value.len - len - prefix);
+ }
- h->value.len = len;
- h->value.data = data;
+ h->value.len = new_len;
return NGX_OK;
}
@@ -1692,6 +2643,8 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
+ conf->upstream.cache_lock = NGX_CONF_UNSET;
+ conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
#endif
conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
@@ -1708,6 +2661,11 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
conf->redirect = NGX_CONF_UNSET;
conf->upstream.change_buffering = 1;
+ conf->cookie_domains = NGX_CONF_UNSET_PTR;
+ conf->cookie_paths = NGX_CONF_UNSET_PTR;
+
+ conf->http_version = NGX_CONF_UNSET_UINT;
+
conf->headers_hash_max_size = NGX_CONF_UNSET_UINT;
conf->headers_hash_bucket_size = NGX_CONF_UNSET_UINT;
@@ -1727,7 +2685,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
size_t size;
ngx_hash_init_t hash;
ngx_http_core_loc_conf_t *clcf;
- ngx_http_proxy_redirect_t *pr;
+ ngx_http_proxy_rewrite_t *pr;
ngx_http_script_compile_t sc;
if (conf->upstream.store != 0) {
@@ -1794,8 +2752,8 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
if (conf->upstream.busy_buffers_size < size) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "\"proxy_busy_buffers_size\" must be equal or bigger than "
- "maximum of the value of \"proxy_buffer_size\" and "
+ "\"proxy_busy_buffers_size\" must be equal to or greater than "
+ "the maximum of the value of \"proxy_buffer_size\" and "
"one of the \"proxy_buffers\"");
return NGX_CONF_ERROR;
@@ -1825,8 +2783,8 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
if (conf->upstream.temp_file_write_size < size) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "\"proxy_temp_file_write_size\" must be equal or bigger than "
- "maximum of the value of \"proxy_buffer_size\" and "
+ "\"proxy_temp_file_write_size\" must be equal to or greater "
+ "than the maximum of the value of \"proxy_buffer_size\" and "
"one of the \"proxy_buffers\"");
return NGX_CONF_ERROR;
@@ -1848,8 +2806,8 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"proxy_max_temp_file_size\" must be equal to zero to disable "
- "the temporary files usage or must be equal or bigger than "
- "maximum of the value of \"proxy_buffer_size\" and "
+ "temporary files usage or must be equal to or greater than "
+ "the maximum of the value of \"proxy_buffer_size\" and "
"one of the \"proxy_buffers\"");
return NGX_CONF_ERROR;
@@ -1940,6 +2898,12 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
conf->cache_key = prev->cache_key;
}
+ ngx_conf_merge_value(conf->upstream.cache_lock,
+ prev->upstream.cache_lock, 0);
+
+ ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
+ prev->upstream.cache_lock_timeout, 5000);
+
#endif
if (conf->method.len == 0) {
@@ -1974,7 +2938,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
if (conf->redirects == NULL && conf->url.data) {
conf->redirects = ngx_array_create(cf->pool, 1,
- sizeof(ngx_http_proxy_redirect_t));
+ sizeof(ngx_http_proxy_rewrite_t));
if (conf->redirects == NULL) {
return NGX_CONF_ERROR;
}
@@ -1984,36 +2948,49 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
return NGX_CONF_ERROR;
}
- pr->handler = ngx_http_proxy_rewrite_redirect_text;
+ ngx_memzero(&pr->pattern.complex,
+ sizeof(ngx_http_complex_value_t));
+
+ ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t));
+
+ pr->handler = ngx_http_proxy_rewrite_complex_handler;
if (conf->vars.uri.len) {
- pr->redirect = conf->url;
- pr->replacement.text = conf->location;
+ pr->pattern.complex.value = conf->url;
+ pr->replacement.value = conf->location;
} else {
- pr->redirect.len = conf->url.len + sizeof("/") - 1;
+ pr->pattern.complex.value.len = conf->url.len
+ + sizeof("/") - 1;
- p = ngx_pnalloc(cf->pool, pr->redirect.len);
+ p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len);
if (p == NULL) {
return NGX_CONF_ERROR;
}
- pr->redirect.data = p;
+ pr->pattern.complex.value.data = p;
p = ngx_cpymem(p, conf->url.data, conf->url.len);
*p = '/';
- ngx_str_set(&pr->replacement.text, "/");
+ ngx_str_set(&pr->replacement.value, "/");
}
}
}
+ ngx_conf_merge_ptr_value(conf->cookie_domains, prev->cookie_domains, NULL);
+
+ ngx_conf_merge_ptr_value(conf->cookie_paths, prev->cookie_paths, NULL);
+
#if (NGX_HTTP_SSL)
if (conf->upstream.ssl == NULL) {
conf->upstream.ssl = prev->upstream.ssl;
}
#endif
+ ngx_conf_merge_uint_value(conf->http_version, prev->http_version,
+ NGX_HTTP_VERSION_10);
+
ngx_conf_merge_uint_value(conf->headers_hash_max_size,
prev->headers_hash_max_size, 512);
@@ -2466,11 +3443,11 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
if (plcf->vars.uri.len) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "\"proxy_pass\" may not have URI part in "
+ "\"proxy_pass\" cannot have URI part in "
"location given by regular expression, "
"or inside named location, "
- "or inside the \"if\" statement, "
- "or inside the \"limit_except\" block");
+ "or inside \"if\" statement, "
+ "or inside \"limit_except\" block");
return NGX_CONF_ERROR;
}
@@ -2488,11 +3465,10 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_proxy_loc_conf_t *plcf = conf;
- u_char *p;
- ngx_str_t *value;
- ngx_array_t *vars_lengths, *vars_values;
- ngx_http_script_compile_t sc;
- ngx_http_proxy_redirect_t *pr;
+ u_char *p;
+ ngx_str_t *value;
+ ngx_http_proxy_rewrite_t *pr;
+ ngx_http_compile_complex_value_t ccv;
if (plcf->redirect == 0) {
return NGX_CONF_OK;
@@ -2526,7 +3502,7 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
if (plcf->redirects == NULL) {
plcf->redirects = ngx_array_create(cf->pool, 1,
- sizeof(ngx_http_proxy_redirect_t));
+ sizeof(ngx_http_proxy_rewrite_t));
if (plcf->redirects == NULL) {
return NGX_CONF_ERROR;
}
@@ -2540,76 +3516,307 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
if (ngx_strcmp(value[1].data, "default") == 0) {
if (plcf->proxy_lengths) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "\"proxy_redirect default\" may not be used "
+ "\"proxy_redirect default\" cannot be used "
"with \"proxy_pass\" directive with variables");
return NGX_CONF_ERROR;
}
if (plcf->url.data == NULL) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "\"proxy_redirect default\" must go "
+ "\"proxy_redirect default\" should be placed "
"after the \"proxy_pass\" directive");
return NGX_CONF_ERROR;
}
- pr->handler = ngx_http_proxy_rewrite_redirect_text;
+ pr->handler = ngx_http_proxy_rewrite_complex_handler;
+
+ ngx_memzero(&pr->pattern.complex, sizeof(ngx_http_complex_value_t));
+
+ ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t));
if (plcf->vars.uri.len) {
- pr->redirect = plcf->url;
- pr->replacement.text = plcf->location;
+ pr->pattern.complex.value = plcf->url;
+ pr->replacement.value = plcf->location;
} else {
- pr->redirect.len = plcf->url.len + sizeof("/") - 1;
+ pr->pattern.complex.value.len = plcf->url.len + sizeof("/") - 1;
- p = ngx_pnalloc(cf->pool, pr->redirect.len);
+ p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len);
if (p == NULL) {
return NGX_CONF_ERROR;
}
- pr->redirect.data = p;
+ pr->pattern.complex.value.data = p;
p = ngx_cpymem(p, plcf->url.data, plcf->url.len);
*p = '/';
- ngx_str_set(&pr->replacement.text, "/");
+ ngx_str_set(&pr->replacement.value, "/");
+ }
+
+ return NGX_CONF_OK;
+ }
+
+
+ if (value[1].data[0] == '~') {
+ value[1].len--;
+ value[1].data++;
+
+ if (value[1].data[0] == '*') {
+ value[1].len--;
+ value[1].data++;
+
+ if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ } else {
+ if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
}
+ } else {
+
+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+ ccv.cf = cf;
+ ccv.value = &value[1];
+ ccv.complex_value = &pr->pattern.complex;
+
+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ pr->handler = ngx_http_proxy_rewrite_complex_handler;
+ }
+
+
+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+ ccv.cf = cf;
+ ccv.value = &value[2];
+ ccv.complex_value = &pr->replacement;
+
+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_proxy_loc_conf_t *plcf = conf;
+
+ ngx_str_t *value;
+ ngx_http_proxy_rewrite_t *pr;
+ ngx_http_compile_complex_value_t ccv;
+
+ if (plcf->cookie_domains == NULL) {
return NGX_CONF_OK;
}
- if (ngx_http_script_variables_count(&value[2]) == 0) {
- pr->handler = ngx_http_proxy_rewrite_redirect_text;
- pr->redirect = value[1];
- pr->replacement.text = value[2];
+ value = cf->args->elts;
+ if (cf->args->nelts == 2) {
+
+ if (ngx_strcmp(value[1].data, "off") == 0) {
+ plcf->cookie_domains = NULL;
+ return NGX_CONF_OK;
+ }
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid parameter \"%V\"", &value[1]);
+ return NGX_CONF_ERROR;
+ }
+
+ if (plcf->cookie_domains == NGX_CONF_UNSET_PTR) {
+ plcf->cookie_domains = ngx_array_create(cf->pool, 1,
+ sizeof(ngx_http_proxy_rewrite_t));
+ if (plcf->cookie_domains == NULL) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ pr = ngx_array_push(plcf->cookie_domains);
+ if (pr == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (value[1].data[0] == '~') {
+ value[1].len--;
+ value[1].data++;
+
+ if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ } else {
+
+ if (value[1].data[0] == '.') {
+ value[1].len--;
+ value[1].data++;
+ }
+
+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+ ccv.cf = cf;
+ ccv.value = &value[1];
+ ccv.complex_value = &pr->pattern.complex;
+
+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ pr->handler = ngx_http_proxy_rewrite_domain_handler;
+
+ if (value[2].data[0] == '.') {
+ value[2].len--;
+ value[2].data++;
+ }
+ }
+
+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+ ccv.cf = cf;
+ ccv.value = &value[2];
+ ccv.complex_value = &pr->replacement;
+
+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_proxy_loc_conf_t *plcf = conf;
+
+ ngx_str_t *value;
+ ngx_http_proxy_rewrite_t *pr;
+ ngx_http_compile_complex_value_t ccv;
+
+ if (plcf->cookie_paths == NULL) {
return NGX_CONF_OK;
}
- ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+ value = cf->args->elts;
- vars_lengths = NULL;
- vars_values = NULL;
+ if (cf->args->nelts == 2) {
- sc.cf = cf;
- sc.source = &value[2];
- sc.lengths = &vars_lengths;
- sc.values = &vars_values;
- sc.complete_lengths = 1;
- sc.complete_values = 1;
+ if (ngx_strcmp(value[1].data, "off") == 0) {
+ plcf->cookie_paths = NULL;
+ return NGX_CONF_OK;
+ }
- if (ngx_http_script_compile(&sc) != NGX_OK) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid parameter \"%V\"", &value[1]);
+ return NGX_CONF_ERROR;
+ }
+
+ if (plcf->cookie_paths == NGX_CONF_UNSET_PTR) {
+ plcf->cookie_paths = ngx_array_create(cf->pool, 1,
+ sizeof(ngx_http_proxy_rewrite_t));
+ if (plcf->cookie_paths == NULL) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ pr = ngx_array_push(plcf->cookie_paths);
+ if (pr == NULL) {
return NGX_CONF_ERROR;
}
- pr->handler = ngx_http_proxy_rewrite_redirect_vars;
- pr->redirect = value[1];
- pr->replacement.vars.lengths = vars_lengths->elts;
- pr->replacement.vars.values = vars_values->elts;
+ if (value[1].data[0] == '~') {
+ value[1].len--;
+ value[1].data++;
+
+ if (value[1].data[0] == '*') {
+ value[1].len--;
+ value[1].data++;
+
+ if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ } else {
+ if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ } else {
+
+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+ ccv.cf = cf;
+ ccv.value = &value[1];
+ ccv.complex_value = &pr->pattern.complex;
+
+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ pr->handler = ngx_http_proxy_rewrite_complex_handler;
+ }
+
+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+ ccv.cf = cf;
+ ccv.value = &value[2];
+ ccv.complex_value = &pr->replacement;
+
+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
return NGX_CONF_OK;
}
+static ngx_int_t
+ngx_http_proxy_rewrite_regex(ngx_conf_t *cf, ngx_http_proxy_rewrite_t *pr,
+ ngx_str_t *regex, ngx_uint_t caseless)
+{
+#if (NGX_PCRE)
+ u_char errstr[NGX_MAX_CONF_ERRSTR];
+ ngx_regex_compile_t rc;
+
+ ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
+
+ rc.pattern = *regex;
+ rc.err.len = NGX_MAX_CONF_ERRSTR;
+ rc.err.data = errstr;
+
+ if (caseless) {
+ rc.options = NGX_REGEX_CASELESS;
+ }
+
+ pr->pattern.regex = ngx_http_regex_compile(cf, &rc);
+ if (pr->pattern.regex == NULL) {
+ return NGX_ERROR;
+ }
+
+ pr->handler = ngx_http_proxy_rewrite_regex_handler;
+
+ return NGX_OK;
+
+#else
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "using regex \"%V\" requires PCRE library", regex);
+ return NGX_ERROR;
+
+#endif
+}
+
+
static char *
ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
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 bb606beb74c..c54c2ffa14c 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
@@ -16,13 +16,7 @@
typedef struct {
- in_addr_t mask;
- in_addr_t addr;
-} ngx_http_realip_from_t;
-
-
-typedef struct {
- ngx_array_t *from; /* array of ngx_http_realip_from_t */
+ ngx_array_t *from; /* array of ngx_in_cidr_t */
ngx_uint_t type;
ngx_uint_t hash;
ngx_str_t header;
@@ -114,9 +108,9 @@ ngx_http_realip_handler(ngx_http_request_t *r)
ngx_list_part_t *part;
ngx_table_elt_t *header;
struct sockaddr_in *sin;
+ ngx_in_cidr_t *from;
ngx_connection_t *c;
ngx_http_realip_ctx_t *ctx;
- ngx_http_realip_from_t *from;
ngx_http_realip_loc_conf_t *rlcf;
ctx = ngx_http_get_module_ctx(r, ngx_http_realip_module);
@@ -317,7 +311,7 @@ ngx_http_realip_from(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ngx_int_t rc;
ngx_str_t *value;
ngx_cidr_t cidr;
- ngx_http_realip_from_t *from;
+ ngx_in_cidr_t *from;
value = cf->args->elts;
@@ -332,7 +326,7 @@ ngx_http_realip_from(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
if (rlcf->from == NULL) {
rlcf->from = ngx_array_create(cf->pool, 2,
- sizeof(ngx_http_realip_from_t));
+ sizeof(ngx_in_cidr_t));
if (rlcf->from == NULL) {
return NGX_CONF_ERROR;
}
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 5fb2ac5ae68..239da6b941e 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
@@ -247,6 +247,20 @@ static ngx_command_t ngx_http_scgi_commands[] = {
offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_methods),
&ngx_http_upstream_cache_method_mask },
+ { ngx_string("scgi_cache_lock"),
+ 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_lock),
+ NULL },
+
+ { ngx_string("scgi_cache_lock_timeout"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_msec_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_lock_timeout),
+ NULL },
+
#endif
{ ngx_string("scgi_temp_path"),
@@ -278,8 +292,8 @@ static ngx_command_t ngx_http_scgi_commands[] = {
&ngx_http_scgi_next_upstream_masks },
{ ngx_string("scgi_param"),
- NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
- ngx_conf_set_keyval_slot,
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE23,
+ ngx_http_upstream_param_set_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_scgi_loc_conf_t, params_source),
NULL },
@@ -519,10 +533,10 @@ static ngx_int_t
ngx_http_scgi_create_request(ngx_http_request_t *r)
{
u_char ch, *key, *val, *lowcase_key;
- size_t len, allocated;
+ size_t len, key_len, val_len, allocated;
ngx_buf_t *b;
ngx_str_t *content_length;
- ngx_uint_t i, n, hash, header_params;
+ ngx_uint_t i, n, hash, skip_empty, header_params;
ngx_chain_t *cl, *body;
ngx_list_part_t *part;
ngx_table_elt_t *header, **ignored;
@@ -554,15 +568,21 @@ ngx_http_scgi_create_request(ngx_http_request_t *r)
while (*(uintptr_t *) le.ip) {
lcode = *(ngx_http_script_len_code_pt *) le.ip;
- len += lcode(&le);
+ key_len = lcode(&le);
- while (*(uintptr_t *) le.ip) {
+ lcode = *(ngx_http_script_len_code_pt *) le.ip;
+ skip_empty = lcode(&le);
+
+ for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
lcode = *(ngx_http_script_len_code_pt *) le.ip;
- len += lcode(&le);
}
- len++;
-
le.ip += sizeof(uintptr_t);
+
+ if (skip_empty && val_len == 0) {
+ continue;
+ }
+
+ len += key_len + val_len + 1;
}
}
@@ -665,7 +685,34 @@ ngx_http_scgi_create_request(ngx_http_request_t *r)
e.request = r;
e.flushed = 1;
- while (*(uintptr_t *) e.ip) {
+ le.ip = scf->params_len->elts;
+
+ while (*(uintptr_t *) le.ip) {
+
+ lcode = *(ngx_http_script_len_code_pt *) le.ip;
+ lcode(&le); /* key length */
+
+ lcode = *(ngx_http_script_len_code_pt *) le.ip;
+ skip_empty = lcode(&le);
+
+ for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
+ lcode = *(ngx_http_script_len_code_pt *) le.ip;
+ }
+ le.ip += sizeof(uintptr_t);
+
+ if (skip_empty && val_len == 0) {
+ e.skip = 1;
+
+ while (*(uintptr_t *) e.ip) {
+ code = *(ngx_http_script_code_pt *) e.ip;
+ code((ngx_http_script_engine_t *) &e);
+ }
+ e.ip += sizeof(uintptr_t);
+
+ e.skip = 0;
+
+ continue;
+ }
#if (NGX_DEBUG)
key = e.pos;
@@ -1032,6 +1079,8 @@ ngx_http_scgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
+ conf->upstream.cache_lock = NGX_CONF_UNSET;
+ conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
#endif
conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
@@ -1124,8 +1173,8 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
if (conf->upstream.busy_buffers_size < size) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "\"scgi_busy_buffers_size\" must be equal or bigger "
- "than maximum of the value of \"scgi_buffer_size\" and "
+ "\"scgi_busy_buffers_size\" must be equal to or greater "
+ "than the maximum of the value of \"scgi_buffer_size\" and "
"one of the \"scgi_buffers\"");
return NGX_CONF_ERROR;
@@ -1155,8 +1204,8 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
if (conf->upstream.temp_file_write_size < size) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "\"scgi_temp_file_write_size\" must be equal or bigger than "
- "maximum of the value of \"scgi_buffer_size\" and "
+ "\"scgi_temp_file_write_size\" must be equal to or greater than "
+ "the maximum of the value of \"scgi_buffer_size\" and "
"one of the \"scgi_buffers\"");
return NGX_CONF_ERROR;
@@ -1178,8 +1227,8 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
&& conf->upstream.max_temp_file_size < size) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"scgi_max_temp_file_size\" must be equal to zero to disable "
- "the temporary files usage or must be equal or bigger than "
- "maximum of the value of \"scgi_buffer_size\" and "
+ "temporary files usage or must be equal to or greater than "
+ "the maximum of the value of \"scgi_buffer_size\" and "
"one of the \"scgi_buffers\"");
return NGX_CONF_ERROR;
@@ -1263,6 +1312,12 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
conf->cache_key = prev->cache_key;
}
+ ngx_conf_merge_value(conf->upstream.cache_lock,
+ prev->upstream.cache_lock, 0);
+
+ ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
+ prev->upstream.cache_lock_timeout, 5000);
+
#endif
ngx_conf_merge_value(conf->upstream.pass_request_headers,
@@ -1320,9 +1375,9 @@ ngx_http_scgi_merge_params(ngx_conf_t *cf, ngx_http_scgi_loc_conf_t *conf,
#if (NGX_HTTP_CACHE)
ngx_array_t params_merged;
#endif
- ngx_keyval_t *src;
ngx_hash_key_t *hk;
ngx_hash_init_t hash;
+ ngx_http_upstream_param_t *src;
ngx_http_script_compile_t sc;
ngx_http_script_copy_code_t *copy;
@@ -1331,7 +1386,8 @@ ngx_http_scgi_merge_params(ngx_conf_t *cf, ngx_http_scgi_loc_conf_t *conf,
if (prev->headers_hash.buckets
#if (NGX_HTTP_CACHE)
- && ((conf->upstream.cache == NULL) == (prev->upstream.cache == NULL))
+ && ((conf->upstream.cache == NULL)
+ == (prev->upstream.cache == NULL))
#endif
)
{
@@ -1383,9 +1439,11 @@ ngx_http_scgi_merge_params(ngx_conf_t *cf, ngx_http_scgi_loc_conf_t *conf,
#if (NGX_HTTP_CACHE)
if (conf->upstream.cache) {
- ngx_keyval_t *h, *s;
+ ngx_keyval_t *h;
+ ngx_http_upstream_param_t *s;
- if (ngx_array_init(&params_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t))
+ if (ngx_array_init(&params_merged, cf->temp_pool, 4,
+ sizeof(ngx_http_upstream_param_t))
!= NGX_OK)
{
return NGX_ERROR;
@@ -1419,7 +1477,9 @@ ngx_http_scgi_merge_params(ngx_conf_t *cf, ngx_http_scgi_loc_conf_t *conf,
return NGX_ERROR;
}
- *s = *h;
+ s->key = h->key;
+ s->value = h->value;
+ s->skip_empty = 0;
next:
@@ -1461,6 +1521,15 @@ ngx_http_scgi_merge_params(ngx_conf_t *cf, ngx_http_scgi_loc_conf_t *conf,
copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
copy->len = src[i].key.len + 1;
+ copy = ngx_array_push_n(conf->params_len,
+ sizeof(ngx_http_script_copy_code_t));
+ if (copy == NULL) {
+ return NGX_ERROR;
+ }
+
+ copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
+ copy->len = src[i].skip_empty;
+
size = (sizeof(ngx_http_script_copy_code_t)
+ src[i].key.len + 1 + sizeof(uintptr_t) - 1)
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_split_clients_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_split_clients_module.c
index f2160b149de..726269c3c73 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_split_clients_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_split_clients_module.c
@@ -97,7 +97,7 @@ ngx_http_split_clients_variable(ngx_http_request_t *r,
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http split: %uD %uD", hash, part[i].percent);
- if (hash < part[i].percent) {
+ if (hash < part[i].percent || part[i].percent == 0) {
*v = part[i].value;
return NGX_OK;
}
@@ -111,8 +111,9 @@ static char *
ngx_conf_split_clients_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
char *rv;
+ uint32_t sum, last;
ngx_str_t *value, name;
- ngx_uint_t i, sum, last;
+ ngx_uint_t i;
ngx_conf_t save;
ngx_http_variable_t *var;
ngx_http_split_clients_ctx_t *ctx;
@@ -175,19 +176,15 @@ ngx_conf_split_clients_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
for (i = 0; i < ctx->parts.nelts; i++) {
sum = part[i].percent ? sum + part[i].percent : 10000;
if (sum > 10000) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "percent sum is more than 100%%");
- return NGX_CONF_ERROR;
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "percent total is greater than 100%%");
+ return NGX_CONF_ERROR;
}
if (part[i].percent) {
- part[i].percent = (uint32_t)
- (last + 0xffffffff / 10000 * part[i].percent);
- } else {
- part[i].percent = 0xffffffff;
+ last += part[i].percent * (uint64_t) 0xffffffff / 10000;
+ part[i].percent = last;
}
-
- last = part[i].percent;
}
return rv;
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 b02300f39f7..219465ae909 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
@@ -714,7 +714,7 @@ ngx_http_ssi_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
if (ctx->params.nelts > NGX_HTTP_SSI_MAX_PARAMS) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
- "too many SSI command paramters: \"%V\"",
+ "too many SSI command parameters: \"%V\"",
&ctx->command);
goto ssi_error;
}
@@ -1204,7 +1204,7 @@ ngx_http_ssi_parse(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx)
if (ctx->value_buf == NULL) {
ctx->param->value.data = ngx_pnalloc(r->pool,
- ctx->value_len);
+ ctx->value_len + 1);
if (ctx->param->value.data == NULL) {
return NGX_ERROR;
}
@@ -1375,6 +1375,16 @@ ngx_http_ssi_parse(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx)
case ssi_quoted_symbol_state:
state = ctx->saved_state;
+ if (ctx->param->value.len == ctx->value_len) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "too long \"%V%c...\" value of \"%V\" "
+ "parameter in \"%V\" SSI command",
+ &ctx->param->value, ch, &ctx->param->key,
+ &ctx->command);
+ state = ssi_error_state;
+ break;
+ }
+
ctx->param->value.data[ctx->param->value.len++] = ch;
break;
@@ -1993,7 +2003,7 @@ ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
if (set && stub) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
- "\"set\" and \"stub\" may not be used together "
+ "\"set\" and \"stub\" cannot be used together "
"in \"include\" SSI command");
return NGX_HTTP_SSI_ERROR;
}
@@ -2001,7 +2011,7 @@ ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
if (wait) {
if (uri == NULL) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
- "\"wait\" may not be used with file=\"%V\"", file);
+ "\"wait\" cannot be used with file=\"%V\"", file);
return NGX_HTTP_SSI_ERROR;
}
@@ -2178,7 +2188,7 @@ ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
} else {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
- "only one subrequest may be waited at the same time");
+ "can only wait for one subrequest at a time");
}
return NGX_OK;
@@ -2886,7 +2896,7 @@ ngx_http_ssi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
prev->ignore_recycled_buffers, 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, 256);
+ ngx_conf_merge_size_value(conf->value_len, prev->value_len, 255);
if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
&prev->types_keys, &prev->types,
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_static_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_static_module.c
index a0e302ad1d5..9d77e43b119 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_static_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_static_module.c
@@ -95,6 +95,10 @@ ngx_http_static_handler(ngx_http_request_t *r)
of.errors = clcf->open_file_cache_errors;
of.events = clcf->open_file_cache_events;
+ if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
!= NGX_OK)
{
@@ -112,6 +116,10 @@ ngx_http_static_handler(ngx_http_request_t *r)
break;
case NGX_EACCES:
+#if (NGX_HAVE_OPENAT)
+ case NGX_EMLINK:
+ case NGX_ELOOP:
+#endif
level = NGX_LOG_ERR;
rc = NGX_HTTP_FORBIDDEN;
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 fd9ecbe0bff..100ea34dd04 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
@@ -186,8 +186,8 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
break;
}
- if (now - peer->accessed > peer->fail_timeout) {
- peer->fails = 0;
+ if (now - peer->checked > peer->fail_timeout) {
+ peer->checked = now;
break;
}
}
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
new file mode 100644
index 00000000000..6fd9ac70a34
--- /dev/null
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_upstream_keepalive_module.c
@@ -0,0 +1,570 @@
+
+/*
+ * Copyright (C) Maxim Dounin
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+typedef struct {
+ ngx_uint_t max_cached;
+ ngx_uint_t single; /* unsigned:1 */
+
+ ngx_queue_t cache;
+ ngx_queue_t free;
+
+ ngx_http_upstream_init_pt original_init_upstream;
+ ngx_http_upstream_init_peer_pt original_init_peer;
+
+} ngx_http_upstream_keepalive_srv_conf_t;
+
+
+typedef struct {
+ ngx_http_upstream_keepalive_srv_conf_t *conf;
+
+ ngx_http_upstream_t *upstream;
+
+ void *data;
+
+ ngx_event_get_peer_pt original_get_peer;
+ ngx_event_free_peer_pt original_free_peer;
+
+#if (NGX_HTTP_SSL)
+ ngx_event_set_peer_session_pt original_set_session;
+ ngx_event_save_peer_session_pt original_save_session;
+#endif
+
+ ngx_uint_t failed; /* unsigned:1 */
+
+} ngx_http_upstream_keepalive_peer_data_t;
+
+
+typedef struct {
+ ngx_http_upstream_keepalive_srv_conf_t *conf;
+
+ ngx_queue_t queue;
+ ngx_connection_t *connection;
+
+ socklen_t socklen;
+ u_char sockaddr[NGX_SOCKADDRLEN];
+
+} ngx_http_upstream_keepalive_cache_t;
+
+
+static ngx_int_t ngx_http_upstream_init_keepalive_peer(ngx_http_request_t *r,
+ ngx_http_upstream_srv_conf_t *us);
+static ngx_int_t ngx_http_upstream_get_keepalive_peer(ngx_peer_connection_t *pc,
+ void *data);
+static void ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc,
+ void *data, ngx_uint_t state);
+
+static void ngx_http_upstream_keepalive_dummy_handler(ngx_event_t *ev);
+static void ngx_http_upstream_keepalive_close_handler(ngx_event_t *ev);
+static void ngx_http_upstream_keepalive_close(ngx_connection_t *c);
+
+
+#if (NGX_HTTP_SSL)
+static ngx_int_t ngx_http_upstream_keepalive_set_session(
+ ngx_peer_connection_t *pc, void *data);
+static void ngx_http_upstream_keepalive_save_session(ngx_peer_connection_t *pc,
+ void *data);
+#endif
+
+static void *ngx_http_upstream_keepalive_create_conf(ngx_conf_t *cf);
+static char *ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+
+
+static ngx_command_t ngx_http_upstream_keepalive_commands[] = {
+
+ { ngx_string("keepalive"),
+ NGX_HTTP_UPS_CONF|NGX_CONF_TAKE12,
+ ngx_http_upstream_keepalive,
+ 0,
+ 0,
+ NULL },
+
+ ngx_null_command
+};
+
+
+static ngx_http_module_t ngx_http_upstream_keepalive_module_ctx = {
+ NULL, /* preconfiguration */
+ NULL, /* postconfiguration */
+
+ NULL, /* create main configuration */
+ NULL, /* init main configuration */
+
+ ngx_http_upstream_keepalive_create_conf, /* create server configuration */
+ NULL, /* merge server configuration */
+
+ NULL, /* create location configuration */
+ NULL /* merge location configuration */
+};
+
+
+ngx_module_t ngx_http_upstream_keepalive_module = {
+ NGX_MODULE_V1,
+ &ngx_http_upstream_keepalive_module_ctx, /* module context */
+ ngx_http_upstream_keepalive_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_upstream_init_keepalive(ngx_conf_t *cf,
+ ngx_http_upstream_srv_conf_t *us)
+{
+ ngx_uint_t i;
+ ngx_http_upstream_keepalive_srv_conf_t *kcf;
+ ngx_http_upstream_keepalive_cache_t *cached;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0,
+ "init keepalive");
+
+ kcf = ngx_http_conf_upstream_srv_conf(us,
+ ngx_http_upstream_keepalive_module);
+
+ if (kcf->original_init_upstream(cf, us) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ kcf->original_init_peer = us->peer.init;
+
+ us->peer.init = ngx_http_upstream_init_keepalive_peer;
+
+ /* allocate cache items and add to free queue */
+
+ cached = ngx_pcalloc(cf->pool,
+ sizeof(ngx_http_upstream_keepalive_cache_t) * kcf->max_cached);
+ if (cached == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_queue_init(&kcf->cache);
+ ngx_queue_init(&kcf->free);
+
+ for (i = 0; i < kcf->max_cached; i++) {
+ ngx_queue_insert_head(&kcf->free, &cached[i].queue);
+ cached[i].conf = kcf;
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_upstream_init_keepalive_peer(ngx_http_request_t *r,
+ ngx_http_upstream_srv_conf_t *us)
+{
+ ngx_http_upstream_keepalive_peer_data_t *kp;
+ ngx_http_upstream_keepalive_srv_conf_t *kcf;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "init keepalive peer");
+
+ kcf = ngx_http_conf_upstream_srv_conf(us,
+ ngx_http_upstream_keepalive_module);
+
+ kp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_keepalive_peer_data_t));
+ if (kp == NULL) {
+ return NGX_ERROR;
+ }
+
+ if (kcf->original_init_peer(r, us) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ kp->conf = kcf;
+ kp->upstream = r->upstream;
+ kp->data = r->upstream->peer.data;
+ kp->original_get_peer = r->upstream->peer.get;
+ kp->original_free_peer = r->upstream->peer.free;
+
+ r->upstream->peer.data = kp;
+ r->upstream->peer.get = ngx_http_upstream_get_keepalive_peer;
+ r->upstream->peer.free = ngx_http_upstream_free_keepalive_peer;
+
+#if (NGX_HTTP_SSL)
+ kp->original_set_session = r->upstream->peer.set_session;
+ kp->original_save_session = r->upstream->peer.save_session;
+ r->upstream->peer.set_session = ngx_http_upstream_keepalive_set_session;
+ r->upstream->peer.save_session = ngx_http_upstream_keepalive_save_session;
+#endif
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_upstream_get_keepalive_peer(ngx_peer_connection_t *pc, void *data)
+{
+ ngx_http_upstream_keepalive_peer_data_t *kp = data;
+ ngx_http_upstream_keepalive_cache_t *item;
+
+ ngx_int_t rc;
+ ngx_queue_t *q, *cache;
+ ngx_connection_t *c;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
+ "get keepalive peer");
+
+ kp->failed = 0;
+
+ /* single pool of cached connections */
+
+ if (kp->conf->single && !ngx_queue_empty(&kp->conf->cache)) {
+
+ q = ngx_queue_head(&kp->conf->cache);
+
+ item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue);
+ c = item->connection;
+
+ ngx_queue_remove(q);
+ ngx_queue_insert_head(&kp->conf->free, q);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
+ "get keepalive peer: using connection %p", c);
+
+ c->idle = 0;
+ c->log = pc->log;
+ c->read->log = pc->log;
+ c->write->log = pc->log;
+ c->pool->log = pc->log;
+
+ pc->connection = c;
+ pc->cached = 1;
+
+ return NGX_DONE;
+ }
+
+ rc = kp->original_get_peer(pc, kp->data);
+
+ if (kp->conf->single || rc != NGX_OK) {
+ return rc;
+ }
+
+ /* search cache for suitable connection */
+
+ cache = &kp->conf->cache;
+
+ for (q = ngx_queue_head(cache);
+ q != ngx_queue_sentinel(cache);
+ q = ngx_queue_next(q))
+ {
+ item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue);
+ c = item->connection;
+
+ if (ngx_memn2cmp((u_char *) &item->sockaddr, (u_char *) pc->sockaddr,
+ item->socklen, pc->socklen)
+ == 0)
+ {
+ ngx_queue_remove(q);
+ ngx_queue_insert_head(&kp->conf->free, q);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
+ "get keepalive peer: using connection %p", c);
+
+ c->idle = 0;
+ c->log = pc->log;
+ c->read->log = pc->log;
+ c->write->log = pc->log;
+ c->pool->log = pc->log;
+
+ pc->connection = c;
+ pc->cached = 1;
+
+ return NGX_DONE;
+ }
+ }
+
+ return NGX_OK;
+}
+
+
+static void
+ngx_http_upstream_free_keepalive_peer(ngx_peer_connection_t *pc, void *data,
+ ngx_uint_t state)
+{
+ ngx_http_upstream_keepalive_peer_data_t *kp = data;
+ ngx_http_upstream_keepalive_cache_t *item;
+
+ ngx_queue_t *q;
+ ngx_connection_t *c;
+ ngx_http_upstream_t *u;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0,
+ "free keepalive peer");
+
+ /* remember failed state - peer.free() may be called more than once */
+
+ if (state & NGX_PEER_FAILED) {
+ kp->failed = 1;
+ }
+
+ /* cache valid connections */
+
+ u = kp->upstream;
+ c = pc->connection;
+
+ if (kp->failed
+ || c == NULL
+ || c->read->eof
+ || c->read->error
+ || c->read->timedout
+ || c->write->error
+ || c->write->timedout)
+ {
+ goto invalid;
+ }
+
+ if (!u->keepalive) {
+ goto invalid;
+ }
+
+ if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
+ goto invalid;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
+ "free keepalive peer: saving connection %p", c);
+
+ if (ngx_queue_empty(&kp->conf->free)) {
+
+ q = ngx_queue_last(&kp->conf->cache);
+ ngx_queue_remove(q);
+
+ item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue);
+
+ ngx_http_upstream_keepalive_close(item->connection);
+
+ } else {
+ q = ngx_queue_head(&kp->conf->free);
+ ngx_queue_remove(q);
+
+ item = ngx_queue_data(q, ngx_http_upstream_keepalive_cache_t, queue);
+ }
+
+ item->connection = c;
+ ngx_queue_insert_head(&kp->conf->cache, q);
+
+ pc->connection = NULL;
+
+ if (c->read->timer_set) {
+ ngx_del_timer(c->read);
+ }
+ if (c->write->timer_set) {
+ ngx_del_timer(c->write);
+ }
+
+ c->write->handler = ngx_http_upstream_keepalive_dummy_handler;
+ c->read->handler = ngx_http_upstream_keepalive_close_handler;
+
+ c->data = item;
+ c->idle = 1;
+ c->log = ngx_cycle->log;
+ c->read->log = ngx_cycle->log;
+ c->write->log = ngx_cycle->log;
+ c->pool->log = ngx_cycle->log;
+
+ item->socklen = pc->socklen;
+ ngx_memcpy(&item->sockaddr, pc->sockaddr, pc->socklen);
+
+ if (c->read->ready) {
+ ngx_http_upstream_keepalive_close_handler(c->read);
+ }
+
+invalid:
+
+ kp->original_free_peer(pc, kp->data, state);
+}
+
+
+static void
+ngx_http_upstream_keepalive_dummy_handler(ngx_event_t *ev)
+{
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
+ "keepalive dummy handler");
+}
+
+
+static void
+ngx_http_upstream_keepalive_close_handler(ngx_event_t *ev)
+{
+ ngx_http_upstream_keepalive_srv_conf_t *conf;
+ ngx_http_upstream_keepalive_cache_t *item;
+
+ int n;
+ char buf[1];
+ ngx_connection_t *c;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
+ "keepalive close handler");
+
+ c = ev->data;
+
+ if (c->close) {
+ goto close;
+ }
+
+ n = recv(c->fd, buf, 1, MSG_PEEK);
+
+ if (n == -1 && ngx_socket_errno == NGX_EAGAIN) {
+ /* stale event */
+
+ if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
+ goto close;
+ }
+
+ return;
+ }
+
+close:
+
+ item = c->data;
+ conf = item->conf;
+
+ ngx_http_upstream_keepalive_close(c);
+
+ ngx_queue_remove(&item->queue);
+ ngx_queue_insert_head(&conf->free, &item->queue);
+}
+
+
+static void
+ngx_http_upstream_keepalive_close(ngx_connection_t *c)
+{
+
+#if (NGX_HTTP_SSL)
+
+ if (c->ssl) {
+ c->ssl->no_wait_shutdown = 1;
+ c->ssl->no_send_shutdown = 1;
+
+ if (ngx_ssl_shutdown(c) == NGX_AGAIN) {
+ c->ssl->handler = ngx_http_upstream_keepalive_close;
+ return;
+ }
+ }
+
+#endif
+
+ ngx_destroy_pool(c->pool);
+ ngx_close_connection(c);
+}
+
+
+#if (NGX_HTTP_SSL)
+
+static ngx_int_t
+ngx_http_upstream_keepalive_set_session(ngx_peer_connection_t *pc, void *data)
+{
+ ngx_http_upstream_keepalive_peer_data_t *kp = data;
+
+ return kp->original_set_session(pc, kp->data);
+}
+
+
+static void
+ngx_http_upstream_keepalive_save_session(ngx_peer_connection_t *pc, void *data)
+{
+ ngx_http_upstream_keepalive_peer_data_t *kp = data;
+
+ kp->original_save_session(pc, kp->data);
+ return;
+}
+
+#endif
+
+
+static void *
+ngx_http_upstream_keepalive_create_conf(ngx_conf_t *cf)
+{
+ ngx_http_upstream_keepalive_srv_conf_t *conf;
+
+ conf = ngx_pcalloc(cf->pool,
+ sizeof(ngx_http_upstream_keepalive_srv_conf_t));
+ if (conf == NULL) {
+ return NULL;
+ }
+
+ /*
+ * set by ngx_pcalloc():
+ *
+ * conf->original_init_upstream = NULL;
+ * conf->original_init_peer = NULL;
+ */
+
+ conf->max_cached = 1;
+
+ return conf;
+}
+
+
+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_int_t n;
+ ngx_str_t *value;
+ ngx_uint_t i;
+
+ 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);
+
+ kcf->original_init_upstream = uscf->peer.init_upstream
+ ? uscf->peer.init_upstream
+ : ngx_http_upstream_init_round_robin;
+
+ uscf->peer.init_upstream = ngx_http_upstream_init_keepalive;
+
+ /* read options */
+
+ value = cf->args->elts;
+
+ n = ngx_atoi(value[1].data, value[1].len);
+
+ if (n == NGX_ERROR || n == 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid value \"%V\" in \"%V\" directive",
+ &value[1], &cmd->name);
+ return NGX_CONF_ERROR;
+ }
+
+ kcf->max_cached = n;
+
+ for (i = 2; i < cf->args->nelts; i++) {
+
+ if (ngx_strcmp(value[i].data, "single") == 0) {
+ kcf->single = 1;
+ continue;
+ }
+
+ goto invalid;
+ }
+
+ return NGX_CONF_OK;
+
+invalid:
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid parameter \"%V\"", &value[i]);
+
+ return NGX_CONF_ERROR;
+}
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_userid_filter_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_userid_filter_module.c
index 05343f2f1a4..1487c091eee 100644
--- a/usr.sbin/nginx/src/http/modules/ngx_http_userid_filter_module.c
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_userid_filter_module.c
@@ -774,14 +774,10 @@ ngx_http_userid_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}
ucf->expires = ngx_parse_time(&value[1], 1);
- if (ucf->expires == NGX_ERROR) {
+ if (ucf->expires == (time_t) NGX_ERROR) {
return "invalid value";
}
- if (ucf->expires == NGX_PARSE_LARGE_TIME) {
- return "value must be less than 68 years";
- }
-
return NGX_CONF_OK;
}
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 fb5ff0d7876..0c999ca6299 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
@@ -43,7 +43,6 @@ static ngx_int_t ngx_http_uwsgi_create_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_uwsgi_reinit_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_uwsgi_process_status_line(ngx_http_request_t *r);
static ngx_int_t ngx_http_uwsgi_process_header(ngx_http_request_t *r);
-static ngx_int_t ngx_http_uwsgi_process_header(ngx_http_request_t *r);
static void ngx_http_uwsgi_abort_request(ngx_http_request_t *r);
static void ngx_http_uwsgi_finalize_request(ngx_http_request_t *r,
ngx_int_t rc);
@@ -275,6 +274,20 @@ static ngx_command_t ngx_http_uwsgi_commands[] = {
offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_methods),
&ngx_http_upstream_cache_method_mask },
+ { ngx_string("uwsgi_cache_lock"),
+ 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_lock),
+ NULL },
+
+ { ngx_string("uwsgi_cache_lock_timeout"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_msec_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_lock_timeout),
+ NULL },
+
#endif
{ ngx_string("uwsgi_temp_path"),
@@ -306,8 +319,8 @@ static ngx_command_t ngx_http_uwsgi_commands[] = {
&ngx_http_uwsgi_next_upstream_masks },
{ ngx_string("uwsgi_param"),
- NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
- ngx_conf_set_keyval_slot,
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE23,
+ ngx_http_upstream_param_set_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_uwsgi_loc_conf_t, params_source),
NULL },
@@ -554,7 +567,7 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r)
{
u_char ch, *lowcase_key;
size_t key_len, val_len, len, allocated;
- ngx_uint_t i, n, hash, header_params;
+ ngx_uint_t i, n, hash, skip_empty, header_params;
ngx_buf_t *b;
ngx_chain_t *cl, *body;
ngx_list_part_t *part;
@@ -584,11 +597,18 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r)
lcode = *(ngx_http_script_len_code_pt *) le.ip;
key_len = lcode(&le);
+ lcode = *(ngx_http_script_len_code_pt *) le.ip;
+ skip_empty = lcode(&le);
+
for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode (&le)) {
lcode = *(ngx_http_script_len_code_pt *) le.ip;
}
le.ip += sizeof(uintptr_t);
+ if (skip_empty && val_len == 0) {
+ continue;
+ }
+
len += 2 + key_len + 2 + val_len;
}
}
@@ -707,11 +727,28 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r)
lcode = *(ngx_http_script_len_code_pt *) le.ip;
key_len = (u_char) lcode (&le);
+ lcode = *(ngx_http_script_len_code_pt *) le.ip;
+ skip_empty = lcode(&le);
+
for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
lcode = *(ngx_http_script_len_code_pt *) le.ip;
}
le.ip += sizeof(uintptr_t);
+ if (skip_empty && val_len == 0) {
+ e.skip = 1;
+
+ while (*(uintptr_t *) e.ip) {
+ code = *(ngx_http_script_code_pt *) e.ip;
+ code((ngx_http_script_engine_t *) &e);
+ }
+ e.ip += sizeof(uintptr_t);
+
+ e.skip = 0;
+
+ continue;
+ }
+
*e.pos++ = (u_char) (key_len & 0xff);
*e.pos++ = (u_char) ((key_len >> 8) & 0xff);
@@ -874,10 +911,7 @@ ngx_http_uwsgi_process_status_line(ngx_http_request_t *r)
}
if (rc == NGX_ERROR) {
- r->http_version = NGX_HTTP_VERSION_9;
-
u->process_header = ngx_http_uwsgi_process_header;
-
return ngx_http_uwsgi_process_header(r);
}
@@ -979,12 +1013,12 @@ ngx_http_uwsgi_process_header(ngx_http_request_t *r)
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http uwsgi header done");
- if (r->http_version > NGX_HTTP_VERSION_9) {
+ u = r->upstream;
+
+ if (u->headers_in.status_n) {
return NGX_OK;
}
- u = r->upstream;
-
if (u->headers_in.status) {
status_line = &u->headers_in.status->value;
@@ -996,20 +1030,15 @@ ngx_http_uwsgi_process_header(ngx_http_request_t *r)
return NGX_HTTP_UPSTREAM_INVALID_HEADER;
}
- r->http_version = NGX_HTTP_VERSION_10;
u->headers_in.status_n = status;
u->headers_in.status_line = *status_line;
} else if (u->headers_in.location) {
- r->http_version = NGX_HTTP_VERSION_10;
u->headers_in.status_n = 302;
ngx_str_set(&u->headers_in.status_line,
"302 Moved Temporarily");
} else {
- ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
- "upstream sent neither valid HTTP/1.0 header "
- "nor \"Status\" header line");
u->headers_in.status_n = 200;
ngx_str_set(&u->headers_in.status_line, "200 OK");
}
@@ -1093,6 +1122,8 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
+ conf->upstream.cache_lock = NGX_CONF_UNSET;
+ conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
#endif
conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
@@ -1185,8 +1216,8 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
if (conf->upstream.busy_buffers_size < size) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "\"uwsgi_busy_buffers_size\" must be equal or bigger "
- "than maximum of the value of \"uwsgi_buffer_size\" and "
+ "\"uwsgi_busy_buffers_size\" must be equal to or greater "
+ "than the maximum of the value of \"uwsgi_buffer_size\" and "
"one of the \"uwsgi_buffers\"");
return NGX_CONF_ERROR;
@@ -1216,8 +1247,8 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
if (conf->upstream.temp_file_write_size < size) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "\"uwsgi_temp_file_write_size\" must be equal or bigger than "
- "maximum of the value of \"uwsgi_buffer_size\" and "
+ "\"uwsgi_temp_file_write_size\" must be equal to or greater than "
+ "the maximum of the value of \"uwsgi_buffer_size\" and "
"one of the \"uwsgi_buffers\"");
return NGX_CONF_ERROR;
@@ -1239,8 +1270,8 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
&& conf->upstream.max_temp_file_size < size) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"uwsgi_max_temp_file_size\" must be equal to zero to disable "
- "the temporary files usage or must be equal or bigger than "
- "maximum of the value of \"uwsgi_buffer_size\" and "
+ "temporary files usage or must be equal to or greater than "
+ "the maximum of the value of \"uwsgi_buffer_size\" and "
"one of the \"uwsgi_buffers\"");
return NGX_CONF_ERROR;
@@ -1324,6 +1355,12 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
conf->cache_key = prev->cache_key;
}
+ ngx_conf_merge_value(conf->upstream.cache_lock,
+ prev->upstream.cache_lock, 0);
+
+ ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
+ prev->upstream.cache_lock_timeout, 5000);
+
#endif
ngx_conf_merge_value(conf->upstream.pass_request_headers,
@@ -1386,9 +1423,9 @@ ngx_http_uwsgi_merge_params(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *conf,
#if (NGX_HTTP_CACHE)
ngx_array_t params_merged;
#endif
- ngx_keyval_t *src;
ngx_hash_key_t *hk;
ngx_hash_init_t hash;
+ ngx_http_upstream_param_t *src;
ngx_http_script_compile_t sc;
ngx_http_script_copy_code_t *copy;
@@ -1397,7 +1434,8 @@ ngx_http_uwsgi_merge_params(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *conf,
if (prev->headers_hash.buckets
#if (NGX_HTTP_CACHE)
- && ((conf->upstream.cache == NULL) == (prev->upstream.cache == NULL))
+ && ((conf->upstream.cache == NULL)
+ == (prev->upstream.cache == NULL))
#endif
)
{
@@ -1449,9 +1487,11 @@ ngx_http_uwsgi_merge_params(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *conf,
#if (NGX_HTTP_CACHE)
if (conf->upstream.cache) {
- ngx_keyval_t *h, *s;
+ ngx_keyval_t *h;
+ ngx_http_upstream_param_t *s;
- if (ngx_array_init(&params_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t))
+ if (ngx_array_init(&params_merged, cf->temp_pool, 4,
+ sizeof(ngx_http_upstream_param_t))
!= NGX_OK)
{
return NGX_ERROR;
@@ -1485,7 +1525,9 @@ ngx_http_uwsgi_merge_params(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *conf,
return NGX_ERROR;
}
- *s = *h;
+ s->key = h->key;
+ s->value = h->value;
+ s->skip_empty = 0;
next:
@@ -1527,6 +1569,15 @@ ngx_http_uwsgi_merge_params(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *conf,
copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
copy->len = src[i].key.len;
+ copy = ngx_array_push_n(conf->params_len,
+ sizeof(ngx_http_script_copy_code_t));
+ if (copy == NULL) {
+ return NGX_ERROR;
+ }
+
+ copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
+ copy->len = src[i].skip_empty;
+
size = (sizeof(ngx_http_script_copy_code_t)
+ src[i].key.len + sizeof(uintptr_t) - 1)
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 f86c3038102..4309a448908 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
@@ -14,6 +14,7 @@
#include <libxslt/xslt.h>
#include <libxslt/xsltInternals.h>
#include <libxslt/transform.h>
+#include <libxslt/variables.h>
#include <libxslt/xsltutils.h>
#if (NGX_HAVE_EXSLT)
@@ -27,38 +28,47 @@
typedef struct {
- u_char *name;
- void *data;
+ u_char *name;
+ void *data;
} ngx_http_xslt_file_t;
typedef struct {
- ngx_array_t dtd_files; /* ngx_http_xslt_file_t */
- ngx_array_t sheet_files; /* ngx_http_xslt_file_t */
+ ngx_array_t dtd_files; /* ngx_http_xslt_file_t */
+ ngx_array_t sheet_files; /* ngx_http_xslt_file_t */
} ngx_http_xslt_filter_main_conf_t;
typedef struct {
- xsltStylesheetPtr stylesheet;
- ngx_array_t params; /* ngx_http_complex_value_t */
+ u_char *name;
+ ngx_http_complex_value_t value;
+ ngx_uint_t quote; /* unsigned quote:1; */
+} ngx_http_xslt_param_t;
+
+
+typedef struct {
+ xsltStylesheetPtr stylesheet;
+ ngx_array_t params; /* ngx_http_xslt_param_t */
} ngx_http_xslt_sheet_t;
typedef struct {
- xmlDtdPtr dtd;
- ngx_array_t sheets; /* ngx_http_xslt_sheet_t */
- ngx_hash_t types;
- ngx_array_t *types_keys;
+ xmlDtdPtr dtd;
+ ngx_array_t sheets; /* ngx_http_xslt_sheet_t */
+ ngx_hash_t types;
+ ngx_array_t *types_keys;
+ ngx_array_t *params; /* ngx_http_xslt_param_t */
} ngx_http_xslt_filter_loc_conf_t;
typedef struct {
- xmlDocPtr doc;
- xmlParserCtxtPtr ctxt;
- ngx_http_request_t *request;
- ngx_array_t params;
+ xmlDocPtr doc;
+ xmlParserCtxtPtr ctxt;
+ xsltTransformContextPtr transform;
+ ngx_http_request_t *request;
+ ngx_array_t params;
- ngx_uint_t done; /* unsigned done:1; */
+ ngx_uint_t done; /* unsigned done:1; */
} ngx_http_xslt_filter_ctx_t;
@@ -76,7 +86,7 @@ static void ngx_cdecl ngx_http_xslt_sax_error(void *data, const char *msg, ...);
static ngx_buf_t *ngx_http_xslt_apply_stylesheet(ngx_http_request_t *r,
ngx_http_xslt_filter_ctx_t *ctx);
static ngx_int_t ngx_http_xslt_params(ngx_http_request_t *r,
- ngx_http_xslt_filter_ctx_t *ctx, ngx_array_t *params);
+ ngx_http_xslt_filter_ctx_t *ctx, ngx_array_t *params, ngx_uint_t final);
static u_char *ngx_http_xslt_content_type(xsltStylesheetPtr s);
static u_char *ngx_http_xslt_encoding(xsltStylesheetPtr s);
static void ngx_http_xslt_cleanup(void *data);
@@ -85,6 +95,8 @@ static char *ngx_http_xslt_entities(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_xslt_stylesheet(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
+static char *ngx_http_xslt_param(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
static void ngx_http_xslt_cleanup_dtd(void *data);
static void ngx_http_xslt_cleanup_stylesheet(void *data);
static void *ngx_http_xslt_filter_create_main_conf(ngx_conf_t *cf);
@@ -117,6 +129,20 @@ static ngx_command_t ngx_http_xslt_filter_commands[] = {
0,
NULL },
+ { ngx_string("xslt_param"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
+ ngx_http_xslt_param,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ 0,
+ NULL },
+
+ { ngx_string("xslt_string_param"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
+ ngx_http_xslt_param,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ 0,
+ (void *) 1 },
+
{ ngx_string("xslt_types"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
ngx_http_types_slot,
@@ -336,15 +362,14 @@ ngx_http_xslt_add_chunk(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx,
"xmlCreatePushParserCtxt() failed");
return NGX_ERROR;
}
+ xmlCtxtUseOptions(ctxt, XML_PARSE_NOENT|XML_PARSE_DTDLOAD
+ |XML_PARSE_NOWARNING);
ctxt->sax->externalSubset = ngx_http_xslt_sax_external_subset;
ctxt->sax->setDocumentLocator = NULL;
- ctxt->sax->warning = NULL;
ctxt->sax->error = ngx_http_xslt_sax_error;
ctxt->sax->fatalError = ngx_http_xslt_sax_error;
ctxt->sax->_private = ctx;
- ctxt->replaceEntities = 1;
- ctxt->loadsubset = 1;
ctx->ctxt = ctxt;
ctx->request = r;
@@ -469,13 +494,31 @@ ngx_http_xslt_apply_stylesheet(ngx_http_request_t *r,
for (i = 0; i < conf->sheets.nelts; i++) {
- if (ngx_http_xslt_params(r, ctx, &sheet[i].params) != NGX_OK) {
+ ctx->transform = xsltNewTransformContext(sheet[i].stylesheet, doc);
+ if (ctx->transform == NULL) {
xmlFreeDoc(doc);
return NULL;
}
- res = xsltApplyStylesheet(sheet[i].stylesheet, doc, ctx->params.elts);
+ if (conf->params
+ && ngx_http_xslt_params(r, ctx, conf->params, 0) != NGX_OK)
+ {
+ xsltFreeTransformContext(ctx->transform);
+ xmlFreeDoc(doc);
+ return NULL;
+ }
+ if (ngx_http_xslt_params(r, ctx, &sheet[i].params, 1) != NGX_OK) {
+ xsltFreeTransformContext(ctx->transform);
+ xmlFreeDoc(doc);
+ return NULL;
+ }
+
+ res = xsltApplyStylesheetUser(sheet[i].stylesheet, doc,
+ ctx->params.elts, NULL, NULL,
+ ctx->transform);
+
+ xsltFreeTransformContext(ctx->transform);
xmlFreeDoc(doc);
if (res == NULL) {
@@ -565,27 +608,68 @@ ngx_http_xslt_apply_stylesheet(ngx_http_request_t *r,
static ngx_int_t
ngx_http_xslt_params(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx,
- ngx_array_t *params)
+ ngx_array_t *params, ngx_uint_t final)
{
- u_char *p, *last, *value, *dst, *src, **s;
- size_t len;
- ngx_uint_t i;
- ngx_str_t string;
- ngx_http_complex_value_t *param;
+ u_char *p, *last, *value, *dst, *src, **s;
+ size_t len;
+ ngx_uint_t i;
+ ngx_str_t string;
+ ngx_http_xslt_param_t *param;
param = params->elts;
for (i = 0; i < params->nelts; i++) {
- if (ngx_http_complex_value(r, &param[i], &string) != NGX_OK) {
+ if (ngx_http_complex_value(r, &param[i].value, &string) != NGX_OK) {
return NGX_ERROR;
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"xslt filter param: \"%s\"", string.data);
+ if (param[i].name) {
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "xslt filter param name: \"%s\"", param[i].name);
+
+ if (param[i].quote) {
+ if (xsltQuoteOneUserParam(ctx->transform, param[i].name,
+ string.data)
+ != 0)
+ {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "xsltQuoteOneUserParam(\"%s\", \"%s\") failed",
+ param[i].name, string.data);
+ return NGX_ERROR;
+ }
+
+ continue;
+ }
+
+ s = ngx_array_push(&ctx->params);
+ if (s == NULL) {
+ return NGX_ERROR;
+ }
+
+ *s = param[i].name;
+
+ s = ngx_array_push(&ctx->params);
+ if (s == NULL) {
+ return NGX_ERROR;
+ }
+
+ *s = string.data;
+
+ continue;
+ }
+
+ /*
+ * parse param1=value1:param2=value2 syntax as used by parameters
+ * specified in xslt_stylesheet directives
+ */
+
p = string.data;
- last = string.data + string.len - 1;
+ last = string.data + string.len;
while (p && *p) {
@@ -641,12 +725,14 @@ ngx_http_xslt_params(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx,
}
}
- s = ngx_array_push(&ctx->params);
- if (s == NULL) {
- return NGX_ERROR;
- }
+ if (final) {
+ s = ngx_array_push(&ctx->params);
+ if (s == NULL) {
+ return NGX_ERROR;
+ }
- *s = NULL;
+ *s = NULL;
+ }
return NGX_OK;
}
@@ -768,7 +854,7 @@ ngx_http_xslt_stylesheet(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ngx_pool_cleanup_t *cln;
ngx_http_xslt_file_t *file;
ngx_http_xslt_sheet_t *sheet;
- ngx_http_complex_value_t *param;
+ ngx_http_xslt_param_t *param;
ngx_http_compile_complex_value_t ccv;
ngx_http_xslt_filter_main_conf_t *xmcf;
@@ -837,7 +923,7 @@ found:
}
if (ngx_array_init(&sheet->params, cf->pool, n - 2,
- sizeof(ngx_http_complex_value_t))
+ sizeof(ngx_http_xslt_param_t))
!= NGX_OK)
{
return NGX_CONF_ERROR;
@@ -850,11 +936,12 @@ found:
return NGX_CONF_ERROR;
}
+ ngx_memzero(param, sizeof(ngx_http_xslt_param_t));
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
ccv.cf = cf;
ccv.value = &value[i];
- ccv.complex_value = param;
+ ccv.complex_value = &param->value;
ccv.zero = 1;
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
@@ -866,6 +953,48 @@ found:
}
+static char *
+ngx_http_xslt_param(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_xslt_filter_loc_conf_t *xlcf = conf;
+
+ ngx_http_xslt_param_t *param;
+ ngx_http_compile_complex_value_t ccv;
+ ngx_str_t *value;
+
+ value = cf->args->elts;
+
+ if (xlcf->params == NULL) {
+ xlcf->params = ngx_array_create(cf->pool, 2,
+ sizeof(ngx_http_xslt_param_t));
+ if (xlcf->params == NULL) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ param = ngx_array_push(xlcf->params);
+ if (param == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ param->name = value[1].data;
+ param->quote = (cmd->post == NULL) ? 0 : 1;
+
+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+ ccv.cf = cf;
+ ccv.value = &value[2];
+ ccv.complex_value = &param->value;
+ ccv.zero = 1;
+
+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
static void
ngx_http_xslt_cleanup_dtd(void *data)
{
@@ -925,6 +1054,7 @@ ngx_http_xslt_filter_create_conf(ngx_conf_t *cf)
* conf->sheets = { NULL };
* conf->types = { NULL };
* conf->types_keys = NULL;
+ * conf->params = NULL;
*/
return conf;
@@ -945,6 +1075,10 @@ ngx_http_xslt_filter_merge_conf(ngx_conf_t *cf, void *parent, void *child)
conf->sheets = prev->sheets;
}
+ if (conf->params == NULL) {
+ conf->params = prev->params;
+ }
+
if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
&prev->types_keys, &prev->types,
ngx_http_xslt_default_types)
diff --git a/usr.sbin/nginx/src/http/modules/perl/nginx.pm b/usr.sbin/nginx/src/http/modules/perl/nginx.pm
index 76ec1d3915b..766b8101787 100644
--- a/usr.sbin/nginx/src/http/modules/perl/nginx.pm
+++ b/usr.sbin/nginx/src/http/modules/perl/nginx.pm
@@ -50,7 +50,7 @@ our @EXPORT = qw(
HTTP_INSUFFICIENT_STORAGE
);
-our $VERSION = '1.0.15';
+our $VERSION = '1.2.0';
require XSLoader;
XSLoader::load('nginx', $VERSION);
@@ -132,6 +132,7 @@ Igor Sysoev
=head1 COPYRIGHT AND LICENSE
Copyright (C) Igor Sysoev
+Copyright (C) Nginx, Inc.
=cut
diff --git a/usr.sbin/nginx/src/http/modules/perl/nginx.xs b/usr.sbin/nginx/src/http/modules/perl/nginx.xs
index dc69d509ae3..ecd11ffbc07 100644
--- a/usr.sbin/nginx/src/http/modules/perl/nginx.xs
+++ b/usr.sbin/nginx/src/http/modules/perl/nginx.xs
@@ -663,6 +663,10 @@ sendfile(r, filename, offset = -1, bytes = 0)
of.errors = clcf->open_file_cache_errors;
of.events = clcf->open_file_cache_events;
+ if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
+ XSRETURN_EMPTY;
+ }
+
if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
!= NGX_OK)
{
diff --git a/usr.sbin/nginx/src/http/ngx_http.c b/usr.sbin/nginx/src/http/ngx_http.c
index 8f45b71c9ed..3e077fb95ab 100644
--- a/usr.sbin/nginx/src/http/ngx_http.c
+++ b/usr.sbin/nginx/src/http/ngx_http.c
@@ -1417,7 +1417,7 @@ ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
/*
* check whether all name-based servers have the same
- * configuraiton as a default server for given address:port
+ * configuration as a default server for given address:port
*/
addr = port[p].addrs.elts;
@@ -1763,6 +1763,13 @@ ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr)
ls->rcvbuf = addr->opt.rcvbuf;
ls->sndbuf = addr->opt.sndbuf;
+ ls->keepalive = addr->opt.so_keepalive;
+#if (NGX_HAVE_KEEPALIVE_TUNABLE)
+ ls->keepidle = addr->opt.tcp_keepidle;
+ ls->keepintvl = addr->opt.tcp_keepintvl;
+ ls->keepcnt = addr->opt.tcp_keepcnt;
+#endif
+
#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
ls->accept_filter = addr->opt.accept_filter;
#endif
diff --git a/usr.sbin/nginx/src/http/ngx_http.h b/usr.sbin/nginx/src/http/ngx_http.h
index 930ac71ce06..f152006a005 100644
--- a/usr.sbin/nginx/src/http/ngx_http.h
+++ b/usr.sbin/nginx/src/http/ngx_http.h
@@ -53,6 +53,7 @@ struct ngx_http_log_ctx_s {
typedef struct {
+ ngx_uint_t http_version;
ngx_uint_t code;
ngx_uint_t count;
u_char *start;
diff --git a/usr.sbin/nginx/src/http/ngx_http_busy_lock.c b/usr.sbin/nginx/src/http/ngx_http_busy_lock.c
index 35a03acaac9..3b4b28c8b32 100644
--- a/usr.sbin/nginx/src/http/ngx_http_busy_lock.c
+++ b/usr.sbin/nginx/src/http/ngx_http_busy_lock.c
@@ -274,7 +274,7 @@ char *ngx_http_set_busy_lock_slot(ngx_conf_t *cf, ngx_command_t *cmd,
line.data = value[i].data + 2;
bl->timeout = ngx_parse_time(&line, 1);
- if (bl->timeout == NGX_ERROR) {
+ if (bl->timeout == (time_t) NGX_ERROR) {
invalid = 1;
break;
}
@@ -300,7 +300,7 @@ char *ngx_http_set_busy_lock_slot(ngx_conf_t *cf, ngx_command_t *cmd,
if (bl->timeout == 0 && bl->max_waiting) {
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
- "busy lock waiting is useless with zero timeout, ignoring");
+ "busy lock waiting is useless with zero timeout, ignoring");
}
return NGX_CONF_OK;
diff --git a/usr.sbin/nginx/src/http/ngx_http_cache.h b/usr.sbin/nginx/src/http/ngx_http_cache.h
index cb5d766882f..2a2d7229153 100644
--- a/usr.sbin/nginx/src/http/ngx_http_cache.h
+++ b/usr.sbin/nginx/src/http/ngx_http_cache.h
@@ -80,6 +80,14 @@ struct ngx_http_cache_s {
ngx_http_file_cache_t *file_cache;
ngx_http_file_cache_node_t *node;
+ ngx_msec_t lock_timeout;
+ ngx_msec_t wait_time;
+
+ ngx_event_t wait_event;
+
+ unsigned lock:1;
+ unsigned waiting:1;
+
unsigned updated:1;
unsigned updating:1;
unsigned exists:1;
@@ -119,8 +127,11 @@ struct ngx_http_file_cache_s {
time_t inactive;
- ngx_msec_t last;
ngx_uint_t files;
+ ngx_uint_t loader_files;
+ ngx_msec_t last;
+ ngx_msec_t loader_sleep;
+ ngx_msec_t loader_threshold;
ngx_shm_zone_t *shm_zone;
};
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 d52fbebe869..95bc0b83564 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
@@ -74,7 +74,7 @@ ngx_module_t ngx_http_copy_filter_module = {
};
-static ngx_http_output_body_filter_pt ngx_http_next_filter;
+static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
static ngx_int_t
@@ -115,7 +115,8 @@ ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in)
ctx->bufs = conf->bufs;
ctx->tag = (ngx_buf_tag_t) &ngx_http_copy_filter_module;
- ctx->output_filter = (ngx_output_chain_filter_pt) ngx_http_next_filter;
+ ctx->output_filter = (ngx_output_chain_filter_pt)
+ ngx_http_next_body_filter;
ctx->filter_ctx = r;
#if (NGX_HAVE_FILE_AIO)
@@ -292,7 +293,7 @@ ngx_http_copy_filter_merge_conf(ngx_conf_t *cf, void *parent, void *child)
static ngx_int_t
ngx_http_copy_filter_init(ngx_conf_t *cf)
{
- ngx_http_next_filter = ngx_http_top_body_filter;
+ ngx_http_next_body_filter = ngx_http_top_body_filter;
ngx_http_top_body_filter = ngx_http_copy_filter;
return NGX_OK;
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 82bb1275c5e..04620229459 100644
--- a/usr.sbin/nginx/src/http/ngx_http_core_module.c
+++ b/usr.sbin/nginx/src/http/ngx_http_core_module.c
@@ -76,6 +76,10 @@ static ngx_uint_t ngx_http_gzip_quantity(u_char *p, u_char *last);
static char *ngx_http_gzip_disable(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
#endif
+#if (NGX_HAVE_OPENAT)
+static char *ngx_http_disable_symlinks(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+#endif
static char *ngx_http_core_lowat_check(ngx_conf_t *cf, void *post, void *data);
static char *ngx_http_core_pool_size(ngx_conf_t *cf, void *post, void *data);
@@ -719,7 +723,7 @@ static ngx_command_t ngx_http_core_commands[] = {
NULL },
{ ngx_string("resolver"),
- NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
ngx_http_core_resolver,
NGX_HTTP_LOC_CONF_OFFSET,
0,
@@ -764,6 +768,17 @@ static ngx_command_t ngx_http_core_commands[] = {
#endif
+#if (NGX_HAVE_OPENAT)
+
+ { ngx_string("disable_symlinks"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
+ ngx_http_disable_symlinks,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ 0,
+ NULL },
+
+#endif
+
ngx_null_command
};
@@ -1213,20 +1228,29 @@ ngx_http_core_try_files_phase(ngx_http_request_t *r,
len = tf->name.len;
}
- /* 16 bytes are preallocation */
- reserve = ngx_abs((ssize_t) (len - r->uri.len)) + alias + 16;
+ if (!alias) {
+ reserve = len > r->uri.len ? len - r->uri.len : 0;
- if (reserve > allocated) {
+#if (NGX_PCRE)
+ } else if (clcf->regex) {
+ reserve = len;
+#endif
- /* we just need to allocate path and to copy a root */
+ } else {
+ reserve = len > r->uri.len - alias ? len - (r->uri.len - alias) : 0;
+ }
- if (ngx_http_map_uri_to_path(r, &path, &root, reserve) == NULL) {
+ if (reserve > allocated || !allocated) {
+
+ /* 16 bytes are preallocation */
+ allocated = reserve + 16;
+
+ if (ngx_http_map_uri_to_path(r, &path, &root, allocated) == NULL) {
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return NGX_OK;
}
name = path.data + root;
- allocated = path.len - root - (r->uri.len - alias);
}
if (tf->values == NULL) {
@@ -1298,6 +1322,11 @@ ngx_http_core_try_files_phase(ngx_http_request_t *r,
of.errors = clcf->open_file_cache_errors;
of.events = clcf->open_file_cache_events;
+ if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
+ ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+ return NGX_OK;
+ }
+
if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
!= NGX_OK)
{
@@ -2456,7 +2485,6 @@ ngx_http_subrequest(ngx_http_request_t *r,
sr->start_sec = tp->sec;
sr->start_msec = tp->msec;
- r->main->subrequests++;
r->main->count++;
*psr = sr;
@@ -2510,6 +2538,7 @@ ngx_http_internal_redirect(ngx_http_request_t *r,
#endif
r->internal = 1;
+ r->valid_unparsed_uri = 0;
r->add_uri_to_alias = 0;
r->main->count++;
@@ -2561,6 +2590,9 @@ ngx_http_named_location(ngx_http_request_t *r, ngx_str_t *name)
r->content_handler = NULL;
r->loc_conf = (*clcfp)->loc_conf;
+ /* clear the modules contexts */
+ ngx_memzero(r->ctx, sizeof(void *) * ngx_http_max_module);
+
ngx_http_update_location_config(r);
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
@@ -2616,6 +2648,56 @@ ngx_http_cleanup_add(ngx_http_request_t *r, size_t size)
}
+ngx_int_t
+ngx_http_set_disable_symlinks(ngx_http_request_t *r,
+ ngx_http_core_loc_conf_t *clcf, ngx_str_t *path, ngx_open_file_info_t *of)
+{
+#if (NGX_HAVE_OPENAT)
+ u_char *p;
+ ngx_str_t from;
+
+ of->disable_symlinks = clcf->disable_symlinks;
+
+ if (clcf->disable_symlinks_from == NULL) {
+ return NGX_OK;
+ }
+
+ if (ngx_http_complex_value(r, clcf->disable_symlinks_from, &from)
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+
+ if (from.len == 0
+ || from.len > path->len
+ || ngx_memcmp(path->data, from.data, from.len) != 0)
+ {
+ return NGX_OK;
+ }
+
+ if (from.len == path->len) {
+ of->disable_symlinks = NGX_DISABLE_SYMLINKS_OFF;
+ return NGX_OK;
+ }
+
+ p = path->data + from.len;
+
+ if (*p == '/') {
+ of->disable_symlinks_from = from.len;
+ return NGX_OK;
+ }
+
+ p--;
+
+ if (*p == '/') {
+ of->disable_symlinks_from = from.len - 1;
+ }
+#endif
+
+ return NGX_OK;
+}
+
+
static char *
ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
{
@@ -3344,6 +3426,11 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf)
#endif
#endif
+#if (NGX_HAVE_OPENAT)
+ clcf->disable_symlinks = NGX_CONF_UNSET_UINT;
+ clcf->disable_symlinks_from = NGX_CONF_UNSET_PTR;
+#endif
+
return clcf;
}
@@ -3494,8 +3581,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_bitmask_value(conf->keepalive_disable,
prev->keepalive_disable,
(NGX_CONF_BITMASK_SET
- |NGX_HTTP_KEEPALIVE_DISABLE_MSIE6
- |NGX_HTTP_KEEPALIVE_DISABLE_SAFARI));
+ |NGX_HTTP_KEEPALIVE_DISABLE_MSIE6));
ngx_conf_merge_uint_value(conf->satisfy, prev->satisfy,
NGX_HTTP_SATISFY_ALL);
ngx_conf_merge_uint_value(conf->if_modified_since, prev->if_modified_since,
@@ -3553,7 +3639,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
* to inherit it in all servers
*/
- prev->resolver = ngx_resolver_create(cf, NULL);
+ prev->resolver = ngx_resolver_create(cf, NULL, 0);
if (prev->resolver == NULL) {
return NGX_CONF_ERROR;
}
@@ -3627,6 +3713,13 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
#endif
#endif
+#if (NGX_HAVE_OPENAT)
+ ngx_conf_merge_uint_value(conf->disable_symlinks, prev->disable_symlinks,
+ NGX_DISABLE_SYMLINKS_OFF);
+ ngx_conf_merge_ptr_value(conf->disable_symlinks_from,
+ prev->disable_symlinks_from, NULL);
+#endif
+
return NGX_CONF_OK;
}
@@ -3831,6 +3924,97 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
#endif
}
+ if (ngx_strncmp(value[n].data, "so_keepalive=", 13) == 0) {
+
+ if (ngx_strcmp(&value[n].data[13], "on") == 0) {
+ lsopt.so_keepalive = 1;
+
+ } else if (ngx_strcmp(&value[n].data[13], "off") == 0) {
+ lsopt.so_keepalive = 2;
+
+ } else {
+
+#if (NGX_HAVE_KEEPALIVE_TUNABLE)
+ u_char *p, *end;
+ ngx_str_t s;
+
+ end = value[n].data + value[n].len;
+ s.data = value[n].data + 13;
+
+ p = ngx_strlchr(s.data, end, ':');
+ if (p == NULL) {
+ p = end;
+ }
+
+ if (p > s.data) {
+ s.len = p - s.data;
+
+ lsopt.tcp_keepidle = ngx_parse_time(&s, 1);
+ if (lsopt.tcp_keepidle == (time_t) NGX_ERROR) {
+ goto invalid_so_keepalive;
+ }
+ }
+
+ s.data = (p < end) ? (p + 1) : end;
+
+ p = ngx_strlchr(s.data, end, ':');
+ if (p == NULL) {
+ p = end;
+ }
+
+ if (p > s.data) {
+ s.len = p - s.data;
+
+ lsopt.tcp_keepintvl = ngx_parse_time(&s, 1);
+ if (lsopt.tcp_keepintvl == (time_t) NGX_ERROR) {
+ goto invalid_so_keepalive;
+ }
+ }
+
+ s.data = (p < end) ? (p + 1) : end;
+
+ if (s.data < end) {
+ s.len = end - s.data;
+
+ lsopt.tcp_keepcnt = ngx_atoi(s.data, s.len);
+ if (lsopt.tcp_keepcnt == NGX_ERROR) {
+ goto invalid_so_keepalive;
+ }
+ }
+
+ if (lsopt.tcp_keepidle == 0 && lsopt.tcp_keepintvl == 0
+ && lsopt.tcp_keepcnt == 0)
+ {
+ goto invalid_so_keepalive;
+ }
+
+ lsopt.so_keepalive = 1;
+
+#else
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "the \"so_keepalive\" parameter accepts "
+ "only \"on\" or \"off\" on this platform");
+ return NGX_CONF_ERROR;
+
+#endif
+ }
+
+ lsopt.set = 1;
+ lsopt.bind = 1;
+
+ continue;
+
+#if (NGX_HAVE_KEEPALIVE_TUNABLE)
+ invalid_so_keepalive:
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid so_keepalive value: \"%s\"",
+ &value[n].data[13]);
+ return NGX_CONF_ERROR;
+#endif
+ }
+
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid parameter \"%V\"", &value[n]);
return NGX_CONF_ERROR;
@@ -4429,7 +4613,7 @@ ngx_http_core_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
s.data = value[i].data + 9;
inactive = ngx_parse_time(&s, 1);
- if (inactive < 0) {
+ if (inactive == (time_t) NGX_ERROR) {
goto failed;
}
@@ -4457,7 +4641,7 @@ ngx_http_core_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
if (max == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "\"open_file_cache\" must have the \"max\" parameter");
+ "\"open_file_cache\" must have the \"max\" parameter");
return NGX_CONF_ERROR;
}
@@ -4475,7 +4659,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;
+ ngx_str_t *value, name;
if (clcf->error_log) {
return "is duplicate";
@@ -4483,7 +4667,14 @@ ngx_http_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
value = cf->args->elts;
- clcf->error_log = ngx_log_create(cf->cycle, &value[1]);
+ if (ngx_strcmp(value[1].data, "stderr") == 0) {
+ ngx_str_null(&name);
+
+ } else {
+ name = value[1];
+ }
+
+ clcf->error_log = ngx_log_create(cf->cycle, &name);
if (clcf->error_log == NULL) {
return NGX_CONF_ERROR;
}
@@ -4516,24 +4707,16 @@ ngx_http_core_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return "invalid value";
}
- if (clcf->keepalive_timeout == (ngx_msec_t) NGX_PARSE_LARGE_TIME) {
- return "value must be less than 597 hours";
- }
-
if (cf->args->nelts == 2) {
return NGX_CONF_OK;
}
clcf->keepalive_header = ngx_parse_time(&value[2], 1);
- if (clcf->keepalive_header == NGX_ERROR) {
+ if (clcf->keepalive_header == (time_t) NGX_ERROR) {
return "invalid value";
}
- if (clcf->keepalive_header == NGX_PARSE_LARGE_TIME) {
- return "value must be less than 68 years";
- }
-
return NGX_CONF_OK;
}
@@ -4558,7 +4741,6 @@ ngx_http_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *clcf = conf;
- ngx_url_t u;
ngx_str_t *value;
if (clcf->resolver) {
@@ -4567,19 +4749,9 @@ ngx_http_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
value = cf->args->elts;
- ngx_memzero(&u, sizeof(ngx_url_t));
-
- u.host = value[1];
- u.port = 53;
-
- if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V: %s", &u.host, u.err);
- return NGX_CONF_ERROR;
- }
-
- clcf->resolver = ngx_resolver_create(cf, &u.addrs[0]);
+ clcf->resolver = ngx_resolver_create(cf, &value[1], cf->args->nelts - 1);
if (clcf->resolver == NULL) {
- return NGX_OK;
+ return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
@@ -4688,6 +4860,100 @@ ngx_http_gzip_disable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
#endif
+#if (NGX_HAVE_OPENAT)
+
+static char *
+ngx_http_disable_symlinks(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_core_loc_conf_t *clcf = conf;
+
+ ngx_str_t *value;
+ ngx_uint_t i;
+ ngx_http_compile_complex_value_t ccv;
+
+ if (clcf->disable_symlinks != NGX_CONF_UNSET_UINT) {
+ return "is duplicate";
+ }
+
+ value = cf->args->elts;
+
+ for (i = 1; i < cf->args->nelts; i++) {
+
+ if (ngx_strcmp(value[i].data, "off") == 0) {
+ clcf->disable_symlinks = NGX_DISABLE_SYMLINKS_OFF;
+ continue;
+ }
+
+ if (ngx_strcmp(value[i].data, "if_not_owner") == 0) {
+ clcf->disable_symlinks = NGX_DISABLE_SYMLINKS_NOTOWNER;
+ continue;
+ }
+
+ if (ngx_strcmp(value[i].data, "on") == 0) {
+ clcf->disable_symlinks = NGX_DISABLE_SYMLINKS_ON;
+ continue;
+ }
+
+ if (ngx_strncmp(value[i].data, "from=", 5) == 0) {
+ value[i].len -= 5;
+ value[i].data += 5;
+
+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+ ccv.cf = cf;
+ ccv.value = &value[i];
+ ccv.complex_value = ngx_palloc(cf->pool,
+ sizeof(ngx_http_complex_value_t));
+ if (ccv.complex_value == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ clcf->disable_symlinks_from = ccv.complex_value;
+
+ continue;
+ }
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid parameter \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ if (clcf->disable_symlinks == NGX_CONF_UNSET_UINT) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"%V\" must have \"off\", \"on\" "
+ "or \"if_not_owner\" parameter",
+ &cmd->name);
+ return NGX_CONF_ERROR;
+ }
+
+ if (cf->args->nelts == 2) {
+ clcf->disable_symlinks_from = NULL;
+ return NGX_CONF_OK;
+ }
+
+ if (clcf->disable_symlinks_from == NGX_CONF_UNSET_PTR) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "duplicate parameters \"%V %V\"",
+ &value[1], &value[2]);
+ return NGX_CONF_ERROR;
+ }
+
+ if (clcf->disable_symlinks == NGX_DISABLE_SYMLINKS_OFF) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"from=\" cannot be used with \"off\" parameter");
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
+
+#endif
+
+
static char *
ngx_http_core_lowat_check(ngx_conf_t *cf, void *post, void *data)
{
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 ffe04a2075c..bfa0b419ece 100644
--- a/usr.sbin/nginx/src/http/ngx_http_core_module.h
+++ b/usr.sbin/nginx/src/http/ngx_http_core_module.h
@@ -78,6 +78,7 @@ typedef struct {
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
unsigned ipv6only:2;
#endif
+ unsigned so_keepalive:2;
int backlog;
int rcvbuf;
@@ -85,6 +86,11 @@ typedef struct {
#if (NGX_HAVE_SETFIB)
int setfib;
#endif
+#if (NGX_HAVE_KEEPALIVE_TUNABLE)
+ int tcp_keepidle;
+ int tcp_keepintvl;
+ int tcp_keepcnt;
+#endif
#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
char *accept_filter;
@@ -398,6 +404,11 @@ struct ngx_http_core_loc_conf_s {
#endif
#endif
+#if (NGX_HAVE_OPENAT)
+ ngx_uint_t disable_symlinks; /* disable_symlinks */
+ ngx_http_complex_value_t *disable_symlinks_from;
+#endif
+
ngx_array_t *error_pages; /* error_page */
ngx_http_try_file_t *try_files; /* try_files */
@@ -499,6 +510,10 @@ ngx_int_t ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *chain);
ngx_int_t ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *chain);
+ngx_int_t ngx_http_set_disable_symlinks(ngx_http_request_t *r,
+ ngx_http_core_loc_conf_t *clcf, ngx_str_t *path, ngx_open_file_info_t *of);
+
+
extern ngx_module_t ngx_http_core_module;
extern ngx_uint_t ngx_http_max_module;
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 68943a87bb4..bd6cebadd12 100644
--- a/usr.sbin/nginx/src/http/ngx_http_file_cache.c
+++ b/usr.sbin/nginx/src/http/ngx_http_file_cache.c
@@ -11,6 +11,9 @@
#include <ngx_md5.h>
+static ngx_int_t ngx_http_file_cache_lock(ngx_http_request_t *r,
+ ngx_http_cache_t *c);
+static void ngx_http_file_cache_lock_wait_handler(ngx_event_t *ev);
static ngx_int_t ngx_http_file_cache_read(ngx_http_request_t *r,
ngx_http_cache_t *c);
static ssize_t ngx_http_file_cache_aio_read(ngx_http_request_t *r,
@@ -31,8 +34,7 @@ static time_t ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache);
static time_t ngx_http_file_cache_expire(ngx_http_file_cache_t *cache);
static void ngx_http_file_cache_delete(ngx_http_file_cache_t *cache,
ngx_queue_t *q, u_char *name);
-static ngx_int_t
- ngx_http_file_cache_loader_sleep(ngx_http_file_cache_t *cache);
+static void ngx_http_file_cache_loader_sleep(ngx_http_file_cache_t *cache);
static ngx_int_t ngx_http_file_cache_noop(ngx_tree_ctx_t *ctx,
ngx_str_t *path);
static ngx_int_t ngx_http_file_cache_manage_file(ngx_tree_ctx_t *ctx,
@@ -183,13 +185,13 @@ ngx_http_file_cache_create(ngx_http_request_t *r)
return NGX_ERROR;
}
+ cln->handler = ngx_http_file_cache_cleanup;
+ cln->data = c;
+
if (ngx_http_file_cache_exists(cache, c) == NGX_ERROR) {
return NGX_ERROR;
}
- cln->handler = ngx_http_file_cache_cleanup;
- cln->data = c;
-
if (ngx_http_file_cache_name(r, cache->path) != NGX_OK) {
return NGX_ERROR;
}
@@ -246,15 +248,24 @@ ngx_http_file_cache_open(ngx_http_request_t *r)
c = r->cache;
+ if (c->waiting) {
+ return NGX_AGAIN;
+ }
+
if (c->buf) {
return ngx_http_file_cache_read(r, c);
}
cache = c->file_cache;
- cln = ngx_pool_cleanup_add(r->pool, 0);
- if (cln == NULL) {
- return NGX_ERROR;
+ if (c->node == NULL) {
+ cln = ngx_pool_cleanup_add(r->pool, 0);
+ if (cln == NULL) {
+ return NGX_ERROR;
+ }
+
+ cln->handler = ngx_http_file_cache_cleanup;
+ cln->data = c;
}
rc = ngx_http_file_cache_exists(cache, c);
@@ -266,9 +277,6 @@ ngx_http_file_cache_open(ngx_http_request_t *r)
return rc;
}
- cln->handler = ngx_http_file_cache_cleanup;
- cln->data = c;
-
if (rc == NGX_AGAIN) {
return NGX_HTTP_CACHE_SCARCE;
}
@@ -308,7 +316,7 @@ ngx_http_file_cache_open(ngx_http_request_t *r)
}
if (!test) {
- return NGX_DECLINED;
+ goto done;
}
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
@@ -332,7 +340,7 @@ ngx_http_file_cache_open(ngx_http_request_t *r)
case NGX_ENOENT:
case NGX_ENOTDIR:
- return rv;
+ goto done;
default:
ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
@@ -356,6 +364,114 @@ ngx_http_file_cache_open(ngx_http_request_t *r)
}
return ngx_http_file_cache_read(r, c);
+
+done:
+
+ if (rv == NGX_DECLINED) {
+ return ngx_http_file_cache_lock(r, c);
+ }
+
+ return rv;
+}
+
+
+static ngx_int_t
+ngx_http_file_cache_lock(ngx_http_request_t *r, ngx_http_cache_t *c)
+{
+ ngx_msec_t now, timer;
+ ngx_http_file_cache_t *cache;
+
+ if (!c->lock) {
+ return NGX_DECLINED;
+ }
+
+ cache = c->file_cache;
+
+ ngx_shmtx_lock(&cache->shpool->mutex);
+
+ if (!c->node->updating) {
+ c->node->updating = 1;
+ c->updating = 1;
+ }
+
+ ngx_shmtx_unlock(&cache->shpool->mutex);
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http file cache lock u:%d wt:%M",
+ c->updating, c->wait_time);
+
+ if (c->updating) {
+ return NGX_DECLINED;
+ }
+
+ c->waiting = 1;
+
+ now = ngx_current_msec;
+
+ if (c->wait_time == 0) {
+ c->wait_time = now + c->lock_timeout;
+
+ c->wait_event.handler = ngx_http_file_cache_lock_wait_handler;
+ c->wait_event.data = r;
+ c->wait_event.log = r->connection->log;
+ }
+
+ timer = c->wait_time - now;
+
+ ngx_add_timer(&c->wait_event, (timer > 500) ? 500 : timer);
+
+ r->main->blocked++;
+
+ return NGX_AGAIN;
+}
+
+
+static void
+ngx_http_file_cache_lock_wait_handler(ngx_event_t *ev)
+{
+ ngx_uint_t wait;
+ ngx_msec_t timer;
+ ngx_http_cache_t *c;
+ ngx_http_request_t *r;
+ ngx_http_file_cache_t *cache;
+
+ r = ev->data;
+ c = r->cache;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0,
+ "http file cache wait handler wt:%M cur:%M",
+ c->wait_time, ngx_current_msec);
+
+ 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");
+ c->lock = 0;
+ goto wakeup;
+ }
+
+ cache = c->file_cache;
+ wait = 0;
+
+ ngx_shmtx_lock(&cache->shpool->mutex);
+
+ if (c->node->updating) {
+ wait = 1;
+ }
+
+ ngx_shmtx_unlock(&cache->shpool->mutex);
+
+ if (wait) {
+ ngx_add_timer(ev, (timer > 500) ? 500 : timer);
+ return;
+ }
+
+wakeup:
+
+ c->waiting = 0;
+ r->main->blocked--;
+ r->connection->write->handler(r->connection->write);
}
@@ -520,13 +636,19 @@ ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, ngx_http_cache_t *c)
ngx_shmtx_lock(&cache->shpool->mutex);
- fcn = ngx_http_file_cache_lookup(cache, c->key);
+ fcn = c->node;
+
+ if (fcn == NULL) {
+ fcn = ngx_http_file_cache_lookup(cache, c->key);
+ }
if (fcn) {
ngx_queue_remove(&fcn->queue);
- fcn->uses++;
- fcn->count++;
+ if (c->node == NULL) {
+ fcn->uses++;
+ fcn->count++;
+ }
if (fcn->error) {
@@ -623,6 +745,10 @@ ngx_http_file_cache_name(ngx_http_request_t *r, ngx_path_t *path)
c = r->cache;
+ if (c->file.name.len) {
+ return NGX_OK;
+ }
+
c->file.name.len = path->name.len + 1 + path->len
+ 2 * NGX_HTTP_CACHE_KEY_LEN;
@@ -954,6 +1080,10 @@ ngx_http_file_cache_free(ngx_http_cache_t *c, ngx_temp_file_t *tf)
}
}
}
+
+ if (c->wait_event.timer_set) {
+ ngx_del_timer(&c->wait_event);
+ }
}
@@ -1267,59 +1397,53 @@ ngx_http_file_cache_loader(void *data)
static ngx_int_t
-ngx_http_file_cache_loader_sleep(ngx_http_file_cache_t *cache)
+ngx_http_file_cache_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path)
+{
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_file_cache_manage_file(ngx_tree_ctx_t *ctx, ngx_str_t *path)
{
- ngx_msec_t elapsed;
+ ngx_msec_t elapsed;
+ ngx_http_file_cache_t *cache;
- if (cache->files++ > 100) {
+ cache = ctx->data;
+
+ if (ngx_http_file_cache_add_file(ctx, path) != NGX_OK) {
+ (void) ngx_http_file_cache_delete_file(ctx, path);
+ }
+ if (++cache->files >= cache->loader_files) {
+ ngx_http_file_cache_loader_sleep(cache);
+
+ } else {
ngx_time_update();
elapsed = ngx_abs((ngx_msec_int_t) (ngx_current_msec - cache->last));
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
- "http file cache manager time: %M", elapsed);
-
- if (elapsed > 200) {
-
- /*
- * if processing 100 files takes more than 200ms,
- * it seems that many operations require disk i/o,
- * therefore sleep 200ms
- */
-
- ngx_msleep(200);
+ "http file cache loader time elapsed: %M", elapsed);
- ngx_time_update();
+ if (elapsed >= cache->loader_threshold) {
+ ngx_http_file_cache_loader_sleep(cache);
}
-
- cache->last = ngx_current_msec;
- cache->files = 0;
}
return (ngx_quit || ngx_terminate) ? NGX_ABORT : NGX_OK;
}
-static ngx_int_t
-ngx_http_file_cache_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path)
-{
- return NGX_OK;
-}
-
-
-static ngx_int_t
-ngx_http_file_cache_manage_file(ngx_tree_ctx_t *ctx, ngx_str_t *path)
+static void
+ngx_http_file_cache_loader_sleep(ngx_http_file_cache_t *cache)
{
- ngx_http_file_cache_t *cache;
+ ngx_msleep(cache->loader_sleep);
- cache = ctx->data;
+ ngx_time_update();
- if (ngx_http_file_cache_add_file(ctx, path) != NGX_OK) {
- (void) ngx_http_file_cache_delete_file(ctx, path);
- }
-
- return ngx_http_file_cache_loader_sleep(cache);
+ cache->last = ngx_current_msec;
+ cache->files = 0;
}
@@ -1468,6 +1592,8 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
time_t inactive;
ssize_t size;
ngx_str_t s, name, *value;
+ ngx_int_t loader_files;
+ ngx_msec_t loader_sleep, loader_threshold;
ngx_uint_t i, n;
ngx_http_file_cache_t *cache;
@@ -1482,6 +1608,9 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}
inactive = 600;
+ loader_files = 100;
+ loader_sleep = 50;
+ loader_threshold = 200;
name.len = 0;
size = 0;
@@ -1571,7 +1700,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
s.data = value[i].data + 9;
inactive = ngx_parse_time(&s, 1);
- if (inactive < 0) {
+ if (inactive == (time_t) NGX_ERROR) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid inactive value \"%V\"", &value[i]);
return NGX_CONF_ERROR;
@@ -1595,6 +1724,48 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
continue;
}
+ if (ngx_strncmp(value[i].data, "loader_files=", 13) == 0) {
+
+ loader_files = ngx_atoi(value[i].data + 13, value[i].len - 13);
+ if (loader_files == NGX_ERROR) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid loader_files value \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ continue;
+ }
+
+ if (ngx_strncmp(value[i].data, "loader_sleep=", 13) == 0) {
+
+ s.len = value[i].len - 13;
+ s.data = value[i].data + 13;
+
+ loader_sleep = ngx_parse_time(&s, 0);
+ if (loader_sleep == (ngx_msec_t) NGX_ERROR) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid loader_sleep value \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ continue;
+ }
+
+ if (ngx_strncmp(value[i].data, "loader_threshold=", 17) == 0) {
+
+ s.len = value[i].len - 17;
+ s.data = value[i].data + 17;
+
+ loader_threshold = ngx_parse_time(&s, 0);
+ if (loader_threshold == (ngx_msec_t) NGX_ERROR) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid loader_threshold value \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ continue;
+ }
+
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid parameter \"%V\"", &value[i]);
return NGX_CONF_ERROR;
@@ -1612,6 +1783,9 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
cache->path->data = cache;
cache->path->conf_file = cf->conf_file->file.name.data;
cache->path->line = cf->conf_file->line;
+ cache->loader_files = loader_files;
+ cache->loader_sleep = loader_sleep;
+ cache->loader_threshold = loader_threshold;
if (ngx_add_path(cf, &cache->path) != NGX_OK) {
return NGX_CONF_ERROR;
@@ -1665,7 +1839,7 @@ ngx_http_file_cache_valid_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
n = cf->args->nelts - 1;
valid = ngx_parse_time(&value[n], 1);
- if (valid < 0) {
+ if (valid == (time_t) NGX_ERROR) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid time value \"%V\"", &value[n]);
return NGX_CONF_ERROR;
diff --git a/usr.sbin/nginx/src/http/ngx_http_parse.c b/usr.sbin/nginx/src/http/ngx_http_parse.c
index 420c9275f4f..0a10a340ed9 100644
--- a/usr.sbin/nginx/src/http/ngx_http_parse.c
+++ b/usr.sbin/nginx/src/http/ngx_http_parse.c
@@ -111,7 +111,10 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
sw_schema,
sw_schema_slash,
sw_schema_slash_slash,
+ sw_host_start,
sw_host,
+ sw_host_end,
+ sw_host_ip_literal,
sw_port,
sw_host_http_09,
sw_after_slash_in_uri,
@@ -324,14 +327,26 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
case sw_schema_slash_slash:
switch (ch) {
case '/':
- r->host_start = p + 1;
- state = sw_host;
+ state = sw_host_start;
break;
default:
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
break;
+ case sw_host_start:
+
+ r->host_start = p;
+
+ if (ch == '[') {
+ state = sw_host_ip_literal;
+ break;
+ }
+
+ state = sw_host;
+
+ /* fall through */
+
case sw_host:
c = (u_char) (ch | 0x20);
@@ -343,6 +358,10 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
break;
}
+ /* fall through */
+
+ case sw_host_end:
+
r->host_end = p;
switch (ch) {
@@ -367,6 +386,47 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
}
break;
+ case sw_host_ip_literal:
+
+ if (ch >= '0' && ch <= '9') {
+ break;
+ }
+
+ c = (u_char) (ch | 0x20);
+ if (c >= 'a' && c <= 'z') {
+ break;
+ }
+
+ switch (ch) {
+ case ':':
+ break;
+ case ']':
+ state = sw_host_end;
+ break;
+ case '-':
+ case '.':
+ case '_':
+ case '~':
+ /* unreserved */
+ break;
+ case '!':
+ case '$':
+ case '&':
+ case '\'':
+ case '(':
+ case ')':
+ case '*':
+ case '+':
+ case ',':
+ case ';':
+ case '=':
+ /* sub-delims */
+ break;
+ default:
+ return NGX_HTTP_PARSE_INVALID_REQUEST;
+ }
+ break;
+
case sw_port:
if (ch >= '0' && ch <= '9') {
break;
@@ -1037,7 +1097,7 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes)
/*
* we use "ch = *p++" inside the cycle, but this operation is safe,
- * because after the URI there is always at least one charcter:
+ * because after the URI there is always at least one character:
* the line feed
*/
@@ -1093,6 +1153,7 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes)
break;
case '+':
r->plus_in_uri = 1;
+ /* fall through */
default:
*u++ = ch;
break;
@@ -1418,6 +1479,7 @@ ngx_http_parse_status_line(ngx_http_request_t *r, ngx_buf_t *b,
return NGX_ERROR;
}
+ r->http_major = ch - '0';
state = sw_major_digit;
break;
@@ -1432,6 +1494,7 @@ ngx_http_parse_status_line(ngx_http_request_t *r, ngx_buf_t *b,
return NGX_ERROR;
}
+ r->http_major = r->http_major * 10 + ch - '0';
break;
/* the first digit of minor HTTP version */
@@ -1440,6 +1503,7 @@ ngx_http_parse_status_line(ngx_http_request_t *r, ngx_buf_t *b,
return NGX_ERROR;
}
+ r->http_minor = ch - '0';
state = sw_minor_digit;
break;
@@ -1454,6 +1518,7 @@ ngx_http_parse_status_line(ngx_http_request_t *r, ngx_buf_t *b,
return NGX_ERROR;
}
+ r->http_minor = r->http_minor * 10 + ch - '0';
break;
/* HTTP status code */
@@ -1531,6 +1596,7 @@ done:
status->end = p;
}
+ status->http_version = r->http_major * 1000 + r->http_minor;
r->state = sw_start;
return NGX_OK;
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 cf49b2fa8ce..85c4b84d027 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
@@ -46,7 +46,7 @@ ngx_module_t ngx_http_postpone_filter_module = {
};
-static ngx_http_output_body_filter_pt ngx_http_next_filter;
+static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
static ngx_int_t
@@ -80,7 +80,7 @@ ngx_http_postpone_filter(ngx_http_request_t *r, ngx_chain_t *in)
if (r->postponed == NULL) {
if (in || c->buffered) {
- return ngx_http_next_filter(r->main, in);
+ return ngx_http_next_body_filter(r->main, in);
}
return NGX_OK;
@@ -116,7 +116,7 @@ ngx_http_postpone_filter(ngx_http_request_t *r, ngx_chain_t *in)
"http postpone filter output \"%V?%V\"",
&r->uri, &r->args);
- if (ngx_http_next_filter(r->main, pr->out) == NGX_ERROR) {
+ if (ngx_http_next_body_filter(r->main, pr->out) == NGX_ERROR) {
return NGX_ERROR;
}
}
@@ -171,7 +171,7 @@ found:
static ngx_int_t
ngx_http_postpone_filter_init(ngx_conf_t *cf)
{
- ngx_http_next_filter = ngx_http_top_body_filter;
+ ngx_http_next_body_filter = ngx_http_top_body_filter;
ngx_http_top_body_filter = ngx_http_postpone_filter;
return NGX_OK;
diff --git a/usr.sbin/nginx/src/http/ngx_http_request.c b/usr.sbin/nginx/src/http/ngx_http_request.c
index 04c4165dedd..052f379ac3d 100644
--- a/usr.sbin/nginx/src/http/ngx_http_request.c
+++ b/usr.sbin/nginx/src/http/ngx_http_request.c
@@ -612,6 +612,8 @@ ngx_http_ssl_handshake_handler(ngx_connection_t *c)
c->ssl->no_wait_shutdown = 1;
+ c->log->action = "reading client request line";
+
c->read->handler = ngx_http_process_request_line;
/* STUB: epoll edge */ c->write->handler = ngx_http_empty_handler;
@@ -1175,7 +1177,7 @@ ngx_http_read_request_header(ngx_http_request_t *r)
if (n == 0) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "client closed prematurely connection");
+ "client prematurely closed connection");
}
if (n == 0 || n == NGX_ERROR) {
@@ -1493,7 +1495,9 @@ ngx_http_process_user_agent(ngx_http_request_t *r, ngx_table_elt_t *h,
} else if (ngx_strstrn(user_agent, "Chrome/", 7 - 1)) {
r->headers_in.chrome = 1;
- } else if (ngx_strstrn(user_agent, "Safari/", 7 - 1)) {
+ } else if (ngx_strstrn(user_agent, "Safari/", 7 - 1)
+ && ngx_strstrn(user_agent, "Mac OS X", 8 - 1))
+ {
r->headers_in.safari = 1;
} else if (ngx_strstrn(user_agent, "Konqueror", 9 - 1)) {
@@ -1675,56 +1679,85 @@ static ssize_t
ngx_http_validate_host(ngx_http_request_t *r, u_char **host, size_t len,
ngx_uint_t alloc)
{
- u_char *h, ch;
- size_t i, last;
- ngx_uint_t dot;
+ u_char *h, ch;
+ size_t i, dot_pos, host_len;
+
+ enum {
+ sw_usual = 0,
+ sw_literal,
+ sw_rest
+ } state;
+
+ dot_pos = len;
+ host_len = len;
- last = len;
h = *host;
- dot = 0;
+
+ state = sw_usual;
for (i = 0; i < len; i++) {
ch = h[i];
- if (ch == '.') {
- if (dot) {
+ switch (ch) {
+
+ case '.':
+ if (dot_pos == i - 1) {
return 0;
}
+ dot_pos = i;
+ break;
- dot = 1;
- continue;
- }
+ case ':':
+ if (state == sw_usual) {
+ host_len = i;
+ state = sw_rest;
+ }
+ break;
- dot = 0;
+ case '[':
+ if (i == 0) {
+ state = sw_literal;
+ }
+ break;
- if (ch == ':') {
- last = i;
- continue;
- }
+ case ']':
+ if (state == sw_literal) {
+ host_len = i + 1;
+ state = sw_rest;
+ }
+ break;
- if (ngx_path_separator(ch) || ch == '\0') {
+ case '\0':
return 0;
- }
- if (ch >= 'A' || ch < 'Z') {
- alloc = 1;
+ default:
+
+ if (ngx_path_separator(ch)) {
+ return 0;
+ }
+
+ if (ch >= 'A' && ch <= 'Z') {
+ alloc = 1;
+ }
+
+ break;
}
}
- if (dot) {
- last--;
+ if (dot_pos == host_len - 1) {
+ host_len--;
}
if (alloc) {
- *host = ngx_pnalloc(r->pool, last) ;
+ *host = ngx_pnalloc(r->pool, host_len);
if (*host == NULL) {
return -1;
}
- ngx_strlow(*host, h, last);
+ ngx_strlow(*host, h, host_len);
}
- return last;
+ return host_len;
}
@@ -1981,6 +2014,7 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
if (r == c->data) {
r->main->count--;
+ r->main->subrequests++;
if (!r->logged) {
@@ -2394,7 +2428,7 @@ closed:
}
ngx_log_error(NGX_LOG_INFO, c->log, err,
- "client closed prematurely connection");
+ "client prematurely closed connection");
ngx_http_finalize_request(r, 0);
}
diff --git a/usr.sbin/nginx/src/http/ngx_http_request.h b/usr.sbin/nginx/src/http/ngx_http_request.h
index f9d449dd1de..70ca6097efa 100644
--- a/usr.sbin/nginx/src/http/ngx_http_request.h
+++ b/usr.sbin/nginx/src/http/ngx_http_request.h
@@ -10,7 +10,7 @@
#define NGX_HTTP_MAX_URI_CHANGES 10
-#define NGX_HTTP_MAX_SUBREQUESTS 50
+#define NGX_HTTP_MAX_SUBREQUESTS 200
/* must be 2^n */
#define NGX_HTTP_LC_HEADER_LEN 32
@@ -479,10 +479,10 @@ struct ngx_http_request_s {
/*
* instead of using the request context data in
- * ngx_http_limit_zone_module and ngx_http_limit_req_module
+ * ngx_http_limit_conn_module and ngx_http_limit_req_module
* we use the single bits in the request structure
*/
- unsigned limit_zone_set:1;
+ unsigned limit_conn_set:1;
unsigned limit_req_set:1;
#if 0
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 ac09d56f197..bddd7c580a8 100644
--- a/usr.sbin/nginx/src/http/ngx_http_request_body.c
+++ b/usr.sbin/nginx/src/http/ngx_http_request_body.c
@@ -303,7 +303,7 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
if (n == 0) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "client closed prematurely connection");
+ "client prematurely closed connection");
}
if (n == 0 || n == NGX_ERROR) {
diff --git a/usr.sbin/nginx/src/http/ngx_http_script.c b/usr.sbin/nginx/src/http/ngx_http_script.c
index 77ac9a629f5..ce290f4ef67 100644
--- a/usr.sbin/nginx/src/http/ngx_http_script.c
+++ b/usr.sbin/nginx/src/http/ngx_http_script.c
@@ -1506,6 +1506,12 @@ ngx_http_script_file_code(ngx_http_script_engine_t *e)
of.errors = clcf->open_file_cache_errors;
of.events = clcf->open_file_cache_events;
+ if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
+ e->ip = ngx_http_script_exit;
+ e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
+ return;
+ }
+
if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
!= NGX_OK)
{
diff --git a/usr.sbin/nginx/src/http/ngx_http_upstream.c b/usr.sbin/nginx/src/http/ngx_http_upstream.c
index ffbbc11ce91..70a4e166856 100644
--- a/usr.sbin/nginx/src/http/ngx_http_upstream.c
+++ b/usr.sbin/nginx/src/http/ngx_http_upstream.c
@@ -73,6 +73,8 @@ static void ngx_http_upstream_finalize_request(ngx_http_request_t *r,
static ngx_int_t ngx_http_upstream_process_header_line(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
+static ngx_int_t ngx_http_upstream_process_content_length(ngx_http_request_t *r,
+ ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_process_set_cookie(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t
@@ -90,6 +92,11 @@ static ngx_int_t ngx_http_upstream_process_buffering(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_process_charset(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
+static ngx_int_t ngx_http_upstream_process_connection(ngx_http_request_t *r,
+ ngx_table_elt_t *h, ngx_uint_t offset);
+static ngx_int_t
+ ngx_http_upstream_process_transfer_encoding(ngx_http_request_t *r,
+ ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_copy_header_line(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t
@@ -97,14 +104,14 @@ static ngx_int_t
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_copy_content_type(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
-static ngx_int_t ngx_http_upstream_copy_content_length(ngx_http_request_t *r,
- ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_copy_last_modified(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_rewrite_location(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
+static ngx_int_t ngx_http_upstream_rewrite_set_cookie(ngx_http_request_t *r,
+ ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
@@ -150,9 +157,9 @@ ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = {
ngx_http_upstream_copy_content_type, 0, 1 },
{ ngx_string("Content-Length"),
- ngx_http_upstream_process_header_line,
+ ngx_http_upstream_process_content_length,
offsetof(ngx_http_upstream_headers_in_t, content_length),
- ngx_http_upstream_copy_content_length, 0, 0 },
+ ngx_http_upstream_ignore_header_line, 0, 0 },
{ ngx_string("Date"),
ngx_http_upstream_process_header_line,
@@ -193,7 +200,7 @@ ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = {
{ ngx_string("Set-Cookie"),
ngx_http_upstream_process_set_cookie, 0,
- ngx_http_upstream_copy_header_line, 0, 1 },
+ ngx_http_upstream_rewrite_set_cookie, 0, 1 },
{ ngx_string("Content-Disposition"),
ngx_http_upstream_ignore_header_line, 0,
@@ -216,7 +223,7 @@ ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = {
offsetof(ngx_http_headers_out_t, accept_ranges), 1 },
{ ngx_string("Connection"),
- ngx_http_upstream_ignore_header_line, 0,
+ ngx_http_upstream_process_connection, 0,
ngx_http_upstream_ignore_header_line, 0, 0 },
{ ngx_string("Keep-Alive"),
@@ -248,6 +255,10 @@ ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = {
ngx_http_upstream_process_charset, 0,
ngx_http_upstream_copy_header_line, 0, 0 },
+ { ngx_string("Transfer-Encoding"),
+ ngx_http_upstream_process_transfer_encoding, 0,
+ ngx_http_upstream_ignore_header_line, 0, 0 },
+
#if (NGX_HTTP_GZIP)
{ ngx_string("Content-Encoding"),
ngx_http_upstream_process_header_line,
@@ -400,6 +411,8 @@ ngx_http_upstream_create(ngx_http_request_t *r)
r->cache = NULL;
#endif
+ u->headers_in.content_length_n = -1;
+
return NGX_OK;
}
@@ -697,6 +710,9 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u)
c->body_start = u->conf->buffer_size;
c->file_cache = u->conf->cache->data;
+ c->lock = u->conf->cache_lock;
+ c->lock_timeout = u->conf->cache_lock_timeout;
+
u->cache_status = NGX_HTTP_CACHE_MISS;
}
@@ -804,6 +820,7 @@ ngx_http_upstream_cache_send(ngx_http_request_t *r, ngx_http_upstream_t *u)
u->buffer.pos += c->header_start;
ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t));
+ u->headers_in.content_length_n = -1;
if (ngx_list_init(&u->headers_in.headers, r->pool, 8,
sizeof(ngx_table_elt_t))
@@ -1140,8 +1157,20 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u)
c->sendfile &= r->connection->sendfile;
u->output.sendfile = c->sendfile;
- c->pool = r->pool;
+ if (c->pool == NULL) {
+
+ /* we need separate pool here to be able to cache SSL connections */
+
+ c->pool = ngx_create_pool(128, r->connection->log);
+ if (c->pool == NULL) {
+ ngx_http_upstream_finalize_request(r, u,
+ NGX_HTTP_INTERNAL_SERVER_ERROR);
+ return;
+ }
+ }
+
c->log = r->connection->log;
+ c->pool->log = c->log;
c->read->log = c->log;
c->write->log = c->log;
@@ -1167,7 +1196,7 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u)
{
/*
* the r->request_body->buf can be reused for one request only,
- * the subrequests should allocate their own temporay bufs
+ * the subrequests should allocate their own temporary bufs
*/
u->output.free = ngx_alloc_chain_link(r->pool);
@@ -1286,7 +1315,10 @@ ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u)
return NGX_ERROR;
}
+ u->keepalive = 0;
+
ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t));
+ u->headers_in.content_length_n = -1;
if (ngx_list_init(&u->headers_in.headers, r->pool, 8,
sizeof(ngx_table_elt_t))
@@ -1869,8 +1901,6 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u)
r->method = NGX_HTTP_GET;
}
- r->valid_unparsed_uri = 0;
-
ngx_http_internal_redirect(r, uri, &args);
ngx_http_finalize_request(r, NGX_DONE);
return NGX_DONE;
@@ -1928,14 +1958,9 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u)
r->headers_out.status = u->headers_in.status_n;
r->headers_out.status_line = u->headers_in.status_line;
- u->headers_in.content_length_n = r->headers_out.content_length_n;
+ r->headers_out.content_length_n = u->headers_in.content_length_n;
- if (r->headers_out.content_length_n != -1) {
- u->length = (size_t) r->headers_out.content_length_n;
-
- } else {
- u->length = NGX_MAX_SIZE_T_VALUE;
- }
+ u->length = u->headers_in.content_length_n;
return NGX_OK;
}
@@ -1999,6 +2024,11 @@ ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r,
}
}
+ if (u->length == 0) {
+ ngx_http_upstream_finalize_request(r, u, 0);
+ return;
+ }
+
if (ngx_handle_read_event(rev, 0) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
@@ -2119,7 +2149,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
return;
}
- if (u->peer.connection->read->ready) {
+ if (u->peer.connection->read->ready || u->length == 0) {
ngx_http_upstream_process_non_buffered_upstream(r, u);
}
}
@@ -2295,6 +2325,15 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
p->send_timeout = clcf->send_timeout;
p->send_lowat = clcf->send_lowat;
+ p->length = -1;
+
+ if (u->input_filter_init
+ && u->input_filter_init(p->input_ctx) != NGX_OK)
+ {
+ ngx_http_upstream_finalize_request(r, u, 0);
+ return;
+ }
+
u->read_event_handler = ngx_http_upstream_process_upstream;
r->write_event_handler = ngx_http_upstream_process_downstream;
@@ -2384,7 +2423,7 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
return;
}
- ngx_chain_update_chains(&u->free_bufs, &u->busy_bufs,
+ ngx_chain_update_chains(r->pool, &u->free_bufs, &u->busy_bufs,
&u->out_bufs, u->output.tag);
}
@@ -2405,10 +2444,6 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
size = b->end - b->last;
- if (size > u->length) {
- size = u->length;
- }
-
if (size && upstream->read->ready) {
n = upstream->recv(upstream, b->last, size);
@@ -2505,7 +2540,7 @@ ngx_http_upstream_non_buffered_filter(void *data, ssize_t bytes)
cl->buf->last = b->last;
cl->buf->tag = u->output.tag;
- if (u->length == NGX_MAX_SIZE_T_VALUE) {
+ if (u->length == -1) {
return NGX_OK;
}
@@ -2650,9 +2685,17 @@ ngx_http_upstream_process_request(ngx_http_request_t *r)
} else if (p->upstream_eof) {
- /* TODO: check length & update cache */
+ tf = u->pipe->temp_file;
- ngx_http_file_cache_update(r, u->pipe->temp_file);
+ if (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);
+
+ } else {
+ ngx_http_file_cache_free(r->cache, tf);
+ }
} else if (p->upstream_error) {
ngx_http_file_cache_free(r->cache, u->pipe->temp_file);
@@ -2799,6 +2842,10 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u,
if (u->peer.cached && ft_type == NGX_HTTP_UPSTREAM_FT_ERROR) {
status = 0;
+ /* TODO: inform balancer instead */
+
+ u->peer.tries++;
+
} else {
switch(ft_type) {
@@ -2873,6 +2920,10 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u,
}
#endif
+ if (u->peer.connection->pool) {
+ ngx_destroy_pool(u->peer.connection->pool);
+ }
+
ngx_close_connection(u->peer.connection);
u->peer.connection = NULL;
}
@@ -2968,6 +3019,10 @@ ngx_http_upstream_finalize_request(ngx_http_request_t *r,
"close http upstream connection: %d",
u->peer.connection->fd);
+ if (u->peer.connection->pool) {
+ ngx_destroy_pool(u->peer.connection->pool);
+ }
+
ngx_close_connection(u->peer.connection);
}
@@ -3065,6 +3120,21 @@ ngx_http_upstream_ignore_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
static ngx_int_t
+ngx_http_upstream_process_content_length(ngx_http_request_t *r,
+ ngx_table_elt_t *h, ngx_uint_t offset)
+{
+ ngx_http_upstream_t *u;
+
+ u = r->upstream;
+
+ u->headers_in.content_length = h;
+ u->headers_in.content_length_n = ngx_atoof(h->value.data, h->value.len);
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
ngx_http_upstream_process_set_cookie(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)
{
@@ -3242,6 +3312,8 @@ ngx_http_upstream_process_accel_expires(ngx_http_request_t *r,
switch (n) {
case 0:
u->cacheable = 0;
+ /* fall through */
+
case NGX_ERROR:
return NGX_OK;
@@ -3343,6 +3415,40 @@ ngx_http_upstream_process_charset(ngx_http_request_t *r, ngx_table_elt_t *h,
static ngx_int_t
+ngx_http_upstream_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h,
+ ngx_uint_t offset)
+{
+ r->upstream->headers_in.connection = h;
+
+ if (ngx_strlcasestrn(h->value.data, h->value.data + h->value.len,
+ (u_char *) "close", 5 - 1)
+ != NULL)
+ {
+ r->upstream->headers_in.connection_close = 1;
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_upstream_process_transfer_encoding(ngx_http_request_t *r,
+ ngx_table_elt_t *h, ngx_uint_t offset)
+{
+ r->upstream->headers_in.transfer_encoding = h;
+
+ if (ngx_strlcasestrn(h->value.data, h->value.data + h->value.len,
+ (u_char *) "chunked", 7 - 1)
+ != NULL)
+ {
+ r->upstream->headers_in.chunked = 1;
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
ngx_http_upstream_copy_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)
{
@@ -3450,26 +3556,6 @@ ngx_http_upstream_copy_content_type(ngx_http_request_t *r, ngx_table_elt_t *h,
static ngx_int_t
-ngx_http_upstream_copy_content_length(ngx_http_request_t *r, ngx_table_elt_t *h,
- ngx_uint_t offset)
-{
- ngx_table_elt_t *ho;
-
- ho = ngx_list_push(&r->headers_out.headers);
- if (ho == NULL) {
- return NGX_ERROR;
- }
-
- *ho = *h;
-
- r->headers_out.content_length = ho;
- r->headers_out.content_length_n = ngx_atoof(h->value.data, h->value.len);
-
- return NGX_OK;
-}
-
-
-static ngx_int_t
ngx_http_upstream_copy_last_modified(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)
{
@@ -3588,6 +3674,27 @@ ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r, ngx_table_elt_t *h,
static ngx_int_t
+ngx_http_upstream_rewrite_set_cookie(ngx_http_request_t *r, ngx_table_elt_t *h,
+ ngx_uint_t offset)
+{
+ ngx_table_elt_t *ho;
+
+ ho = ngx_list_push(&r->headers_out.headers);
+ if (ho == NULL) {
+ return NGX_ERROR;
+ }
+
+ *ho = *h;
+
+ if (r->upstream->rewrite_cookie) {
+ return r->upstream->rewrite_cookie(r, ho);
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset)
{
@@ -4163,7 +4270,7 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
fail_timeout = ngx_parse_time(&s, 1);
- if (fail_timeout == NGX_ERROR) {
+ if (fail_timeout == (time_t) NGX_ERROR) {
goto invalid;
}
@@ -4355,12 +4462,58 @@ ngx_http_upstream_bind_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
case NGX_DECLINED:
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid address \"%V\"", &value[1]);
+ /* fall through */
+
default:
return NGX_CONF_ERROR;
}
}
+char *
+ngx_http_upstream_param_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf)
+{
+ char *p = conf;
+
+ ngx_str_t *value;
+ ngx_array_t **a;
+ ngx_http_upstream_param_t *param;
+
+ a = (ngx_array_t **) (p + cmd->offset);
+
+ if (*a == NULL) {
+ *a = ngx_array_create(cf->pool, 4, sizeof(ngx_http_upstream_param_t));
+ if (*a == NULL) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ param = ngx_array_push(*a);
+ if (param == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ value = cf->args->elts;
+
+ param->key = value[1];
+ param->value = value[2];
+ param->skip_empty = 0;
+
+ if (cf->args->nelts == 4) {
+ if (ngx_strcmp(value[3].data, "if_not_empty") != 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid parameter \"%V\"", &value[3]);
+ return NGX_CONF_ERROR;
+ }
+
+ param->skip_empty = 1;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
ngx_int_t
ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf,
ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev,
diff --git a/usr.sbin/nginx/src/http/ngx_http_upstream.h b/usr.sbin/nginx/src/http/ngx_http_upstream.h
index 17fe538bdbf..f32c9852269 100644
--- a/usr.sbin/nginx/src/http/ngx_http_upstream.h
+++ b/usr.sbin/nginx/src/http/ngx_http_upstream.h
@@ -166,6 +166,9 @@ typedef struct {
ngx_uint_t cache_use_stale;
ngx_uint_t cache_methods;
+ ngx_flag_t cache_lock;
+ ngx_msec_t cache_lock_timeout;
+
ngx_array_t *cache_valid;
ngx_array_t *cache_bypass;
ngx_array_t *no_cache;
@@ -221,6 +224,7 @@ typedef struct {
ngx_table_elt_t *location;
ngx_table_elt_t *accept_ranges;
ngx_table_elt_t *www_authenticate;
+ ngx_table_elt_t *transfer_encoding;
#if (NGX_HTTP_GZIP)
ngx_table_elt_t *content_encoding;
@@ -229,6 +233,9 @@ typedef struct {
off_t content_length_n;
ngx_array_t cache_control;
+
+ unsigned connection_close:1;
+ unsigned chunked:1;
} ngx_http_upstream_headers_in_t;
@@ -271,7 +278,7 @@ struct ngx_http_upstream_s {
ngx_http_upstream_resolved_t *resolved;
ngx_buf_t buffer;
- size_t length;
+ off_t length;
ngx_chain_t *out_bufs;
ngx_chain_t *busy_bufs;
@@ -292,6 +299,8 @@ struct ngx_http_upstream_s {
ngx_int_t rc);
ngx_int_t (*rewrite_redirect)(ngx_http_request_t *r,
ngx_table_elt_t *h, size_t prefix);
+ ngx_int_t (*rewrite_cookie)(ngx_http_request_t *r,
+ ngx_table_elt_t *h);
ngx_msec_t timeout;
@@ -312,6 +321,7 @@ struct ngx_http_upstream_s {
#endif
unsigned buffering:1;
+ unsigned keepalive:1;
unsigned request_sent:1;
unsigned header_sent:1;
@@ -324,6 +334,13 @@ typedef struct {
} ngx_http_upstream_next_t;
+typedef struct {
+ ngx_str_t key;
+ ngx_str_t value;
+ ngx_uint_t skip_empty;
+} ngx_http_upstream_param_t;
+
+
ngx_int_t ngx_http_upstream_header_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
@@ -333,6 +350,8 @@ ngx_http_upstream_srv_conf_t *ngx_http_upstream_add(ngx_conf_t *cf,
ngx_url_t *u, ngx_uint_t flags);
char *ngx_http_upstream_bind_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
+char *ngx_http_upstream_param_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
ngx_int_t ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf,
ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev,
ngx_str_t *default_hide_headers, ngx_hash_init_t *hash);
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 afc9b2e085a..f0fac873699 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
@@ -49,6 +49,13 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
n += server[i].naddrs;
}
+ if (n == 0) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "no servers in upstream \"%V\" in %s:%ui",
+ &us->host, us->file_name, us->line);
+ return NGX_ERROR;
+ }
+
peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t)
+ sizeof(ngx_http_upstream_rr_peer_t) * (n - 1));
if (peers == NULL) {
@@ -444,8 +451,8 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
break;
}
- if (now - peer->accessed > peer->fail_timeout) {
- peer->fails = 0;
+ if (now - peer->checked > peer->fail_timeout) {
+ peer->checked = now;
break;
}
@@ -492,8 +499,8 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
break;
}
- if (now - peer->accessed > peer->fail_timeout) {
- peer->fails = 0;
+ if (now - peer->checked > peer->fail_timeout) {
+ peer->checked = now;
break;
}
@@ -664,15 +671,16 @@ ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data,
return;
}
+ peer = &rrp->peers->peer[rrp->current];
+
if (state & NGX_PEER_FAILED) {
now = ngx_time();
- peer = &rrp->peers->peer[rrp->current];
-
/* ngx_lock_mutex(rrp->peers->mutex); */
peer->fails++;
peer->accessed = now;
+ peer->checked = now;
if (peer->max_fails) {
peer->current_weight -= peer->weight / peer->max_fails;
@@ -687,6 +695,14 @@ ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data,
}
/* ngx_unlock_mutex(rrp->peers->mutex); */
+
+ } else {
+
+ /* mark peer live if check passed */
+
+ if (peer->accessed < peer->checked) {
+ peer->fails = 0;
+ }
}
rrp->current++;
diff --git a/usr.sbin/nginx/src/http/ngx_http_upstream_round_robin.h b/usr.sbin/nginx/src/http/ngx_http_upstream_round_robin.h
index 6d285ab75e1..4b70f2f5bac 100644
--- a/usr.sbin/nginx/src/http/ngx_http_upstream_round_robin.h
+++ b/usr.sbin/nginx/src/http/ngx_http_upstream_round_robin.h
@@ -24,6 +24,7 @@ typedef struct {
ngx_uint_t fails;
time_t accessed;
+ time_t checked;
ngx_uint_t max_fails;
time_t fail_timeout;
diff --git a/usr.sbin/nginx/src/http/ngx_http_variables.c b/usr.sbin/nginx/src/http/ngx_http_variables.c
index a9eb0afb719..949cef9107c 100644
--- a/usr.sbin/nginx/src/http/ngx_http_variables.c
+++ b/usr.sbin/nginx/src/http/ngx_http_variables.c
@@ -34,6 +34,10 @@ static ngx_int_t ngx_http_variable_cookie(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_argument(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
+#if (NGX_HAVE_TCP_INFO)
+static ngx_int_t ngx_http_variable_tcpinfo(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data);
+#endif
static ngx_int_t ngx_http_variable_host(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
@@ -49,6 +53,8 @@ static ngx_int_t ngx_http_variable_server_port(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_scheme(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_variable_https(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_is_args(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_document_root(ngx_http_request_t *r,
@@ -106,7 +112,7 @@ static ngx_int_t ngx_http_variable_pid(ngx_http_request_t *r,
/*
* the $http_host, $http_user_agent, $http_referer, $http_via,
* and $http_x_forwarded_for variables may be handled by generic
- * ngx_http_variable_unknown_header_in(), but for perfomance reasons
+ * ngx_http_variable_unknown_header_in(), but for performance reasons
* they are handled using dedicated entries
*/
@@ -158,6 +164,8 @@ static ngx_http_variable_t ngx_http_core_variables[] = {
{ ngx_string("scheme"), NULL, ngx_http_variable_scheme, 0, 0, 0 },
+ { ngx_string("https"), NULL, ngx_http_variable_https, 0, 0, 0 },
+
{ ngx_string("request_uri"), NULL, ngx_http_variable_request,
offsetof(ngx_http_request_t, unparsed_uri), 0, 0 },
@@ -255,6 +263,20 @@ static ngx_http_variable_t ngx_http_core_variables[] = {
{ ngx_string("pid"), NULL, ngx_http_variable_pid,
0, 0, 0 },
+#if (NGX_HAVE_TCP_INFO)
+ { ngx_string("tcpinfo_rtt"), NULL, ngx_http_variable_tcpinfo,
+ 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
+
+ { ngx_string("tcpinfo_rttvar"), NULL, ngx_http_variable_tcpinfo,
+ 1, NGX_HTTP_VAR_NOCACHEABLE, 0 },
+
+ { ngx_string("tcpinfo_snd_cwnd"), NULL, ngx_http_variable_tcpinfo,
+ 2, NGX_HTTP_VAR_NOCACHEABLE, 0 },
+
+ { ngx_string("tcpinfo_rcv_space"), NULL, ngx_http_variable_tcpinfo,
+ 3, NGX_HTTP_VAR_NOCACHEABLE, 0 },
+#endif
+
{ ngx_null_string, NULL, NULL, 0, 0, 0 }
};
@@ -380,7 +402,7 @@ ngx_http_get_variable_index(ngx_conf_t *cf, ngx_str_t *name)
v->flags = 0;
v->index = cmcf->variables.nelts - 1;
- return cmcf->variables.nelts - 1;
+ return v->index;
}
@@ -880,6 +902,61 @@ ngx_http_variable_argument(ngx_http_request_t *r, ngx_http_variable_value_t *v,
}
+#if (NGX_HAVE_TCP_INFO)
+
+static ngx_int_t
+ngx_http_variable_tcpinfo(ngx_http_request_t *r, ngx_http_variable_value_t *v,
+ uintptr_t data)
+{
+ struct tcp_info ti;
+ socklen_t len;
+ uint32_t value;
+
+ len = sizeof(struct tcp_info);
+ if (getsockopt(r->connection->fd, IPPROTO_TCP, TCP_INFO, &ti, &len) == -1) {
+ v->not_found = 1;
+ return NGX_OK;
+ }
+
+ v->data = ngx_pnalloc(r->pool, NGX_INT32_LEN);
+ if (v->data == NULL) {
+ return NGX_ERROR;
+ }
+
+ switch (data) {
+ case 0:
+ value = ti.tcpi_rtt;
+ break;
+
+ case 1:
+ value = ti.tcpi_rttvar;
+ break;
+
+ case 2:
+ value = ti.tcpi_snd_cwnd;
+ break;
+
+ case 3:
+ value = ti.tcpi_rcv_space;
+ break;
+
+ /* suppress warning */
+ default:
+ value = 0;
+ break;
+ }
+
+ v->len = ngx_sprintf(v->data, "%uD", value) - v->data;
+ v->valid = 1;
+ v->no_cacheable = 0;
+ v->not_found = 0;
+
+ return NGX_OK;
+}
+
+#endif
+
+
static ngx_int_t
ngx_http_variable_host(ngx_http_request_t *r, ngx_http_variable_value_t *v,
uintptr_t data)
@@ -1109,6 +1186,30 @@ ngx_http_variable_scheme(ngx_http_request_t *r,
static ngx_int_t
+ngx_http_variable_https(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data)
+{
+#if (NGX_HTTP_SSL)
+
+ if (r->connection->ssl) {
+ v->len = sizeof("on") - 1;
+ v->valid = 1;
+ v->no_cacheable = 0;
+ v->not_found = 0;
+ v->data = (u_char *) "on";
+
+ return NGX_OK;
+ }
+
+#endif
+
+ *v = ngx_http_variable_null_value;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
ngx_http_variable_is_args(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
@@ -1172,10 +1273,13 @@ static ngx_int_t
ngx_http_variable_realpath_root(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
+ u_char *real;
size_t len;
ngx_str_t path;
ngx_http_core_loc_conf_t *clcf;
- u_char real[NGX_MAX_PATH];
+#if (NGX_HAVE_MAX_PATH)
+ u_char buffer[NGX_MAX_PATH];
+#endif
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
@@ -1197,7 +1301,15 @@ ngx_http_variable_realpath_root(ngx_http_request_t *r,
}
}
- if (ngx_realpath(path.data, real) == NULL) {
+#if (NGX_HAVE_MAX_PATH)
+ real = buffer;
+#else
+ real = NULL;
+#endif
+
+ real = ngx_realpath(path.data, real);
+
+ if (real == NULL) {
ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
ngx_realpath_n " \"%s\" failed", path.data);
return NGX_ERROR;
@@ -1207,6 +1319,9 @@ ngx_http_variable_realpath_root(ngx_http_request_t *r,
v->data = ngx_pnalloc(r->pool, len);
if (v->data == NULL) {
+#if !(NGX_HAVE_MAX_PATH)
+ ngx_free(real);
+#endif
return NGX_ERROR;
}
@@ -1217,6 +1332,10 @@ ngx_http_variable_realpath_root(ngx_http_request_t *r,
ngx_memcpy(v->data, real, len);
+#if !(NGX_HAVE_MAX_PATH)
+ ngx_free(real);
+#endif
+
return NGX_OK;
}
diff --git a/usr.sbin/nginx/src/mail/ngx_mail.c b/usr.sbin/nginx/src/mail/ngx_mail.c
index c94281a15a2..49ec2e05b4d 100644
--- a/usr.sbin/nginx/src/mail/ngx_mail.c
+++ b/usr.sbin/nginx/src/mail/ngx_mail.c
@@ -309,6 +309,12 @@ found:
addr->ctx = listen->ctx;
addr->bind = listen->bind;
addr->wildcard = listen->wildcard;
+ addr->so_keepalive = listen->so_keepalive;
+#if (NGX_HAVE_KEEPALIVE_TUNABLE)
+ addr->tcp_keepidle = listen->tcp_keepidle;
+ addr->tcp_keepintvl = listen->tcp_keepintvl;
+ addr->tcp_keepcnt = listen->tcp_keepcnt;
+#endif
#if (NGX_MAIL_SSL)
addr->ssl = listen->ssl;
#endif
@@ -374,6 +380,13 @@ ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports)
ls->log.data = &ls->addr_text;
ls->log.handler = ngx_accept_log_error;
+ ls->keepalive = addr[i].so_keepalive;
+#if (NGX_HAVE_KEEPALIVE_TUNABLE)
+ ls->keepidle = addr[i].tcp_keepidle;
+ ls->keepintvl = addr[i].tcp_keepintvl;
+ ls->keepcnt = addr[i].tcp_keepcnt;
+#endif
+
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
ls->ipv6only = addr[i].ipv6only;
#endif
diff --git a/usr.sbin/nginx/src/mail/ngx_mail.h b/usr.sbin/nginx/src/mail/ngx_mail.h
index 46a42dff62c..1fceb42856e 100644
--- a/usr.sbin/nginx/src/mail/ngx_mail.h
+++ b/usr.sbin/nginx/src/mail/ngx_mail.h
@@ -41,6 +41,12 @@ typedef struct {
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
unsigned ipv6only:2;
#endif
+ unsigned so_keepalive:2;
+#if (NGX_HAVE_KEEPALIVE_TUNABLE)
+ int tcp_keepidle;
+ int tcp_keepintvl;
+ int tcp_keepcnt;
+#endif
} ngx_mail_listen_t;
@@ -96,6 +102,12 @@ typedef struct {
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
unsigned ipv6only:2;
#endif
+ unsigned so_keepalive:2;
+#if (NGX_HAVE_KEEPALIVE_TUNABLE)
+ int tcp_keepidle;
+ int tcp_keepintvl;
+ int tcp_keepcnt;
+#endif
} ngx_mail_conf_addr_t;
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 c3528599cb0..f79913b0a46 100644
--- a/usr.sbin/nginx/src/mail/ngx_mail_core_module.c
+++ b/usr.sbin/nginx/src/mail/ngx_mail_core_module.c
@@ -25,6 +25,12 @@ static char *ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
+static ngx_conf_deprecated_t ngx_conf_deprecated_so_keepalive = {
+ ngx_conf_deprecated, "so_keepalive",
+ "so_keepalive\" parameter of the \"listen"
+};
+
+
static ngx_command_t ngx_mail_core_commands[] = {
{ ngx_string("server"),
@@ -53,7 +59,7 @@ static ngx_command_t ngx_mail_core_commands[] = {
ngx_conf_set_flag_slot,
NGX_MAIL_SRV_CONF_OFFSET,
offsetof(ngx_mail_core_srv_conf_t, so_keepalive),
- NULL },
+ &ngx_conf_deprecated_so_keepalive },
{ ngx_string("timeout"),
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
@@ -70,7 +76,7 @@ static ngx_command_t ngx_mail_core_commands[] = {
NULL },
{ ngx_string("resolver"),
- NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
+ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
ngx_mail_core_resolver,
NGX_MAIL_SRV_CONF_OFFSET,
0,
@@ -447,6 +453,96 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
#endif
}
+ if (ngx_strncmp(value[i].data, "so_keepalive=", 13) == 0) {
+
+ if (ngx_strcmp(&value[i].data[13], "on") == 0) {
+ ls->so_keepalive = 1;
+
+ } else if (ngx_strcmp(&value[i].data[13], "off") == 0) {
+ ls->so_keepalive = 2;
+
+ } else {
+
+#if (NGX_HAVE_KEEPALIVE_TUNABLE)
+ u_char *p, *end;
+ ngx_str_t s;
+
+ end = value[i].data + value[i].len;
+ s.data = value[i].data + 13;
+
+ p = ngx_strlchr(s.data, end, ':');
+ if (p == NULL) {
+ p = end;
+ }
+
+ if (p > s.data) {
+ s.len = p - s.data;
+
+ ls->tcp_keepidle = ngx_parse_time(&s, 1);
+ if (ls->tcp_keepidle == (time_t) NGX_ERROR) {
+ goto invalid_so_keepalive;
+ }
+ }
+
+ s.data = (p < end) ? (p + 1) : end;
+
+ p = ngx_strlchr(s.data, end, ':');
+ if (p == NULL) {
+ p = end;
+ }
+
+ if (p > s.data) {
+ s.len = p - s.data;
+
+ ls->tcp_keepintvl = ngx_parse_time(&s, 1);
+ if (ls->tcp_keepintvl == (time_t) NGX_ERROR) {
+ goto invalid_so_keepalive;
+ }
+ }
+
+ s.data = (p < end) ? (p + 1) : end;
+
+ if (s.data < end) {
+ s.len = end - s.data;
+
+ ls->tcp_keepcnt = ngx_atoi(s.data, s.len);
+ if (ls->tcp_keepcnt == NGX_ERROR) {
+ goto invalid_so_keepalive;
+ }
+ }
+
+ if (ls->tcp_keepidle == 0 && ls->tcp_keepintvl == 0
+ && ls->tcp_keepcnt == 0)
+ {
+ goto invalid_so_keepalive;
+ }
+
+ ls->so_keepalive = 1;
+
+#else
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "the \"so_keepalive\" parameter accepts "
+ "only \"on\" or \"off\" on this platform");
+ return NGX_CONF_ERROR;
+
+#endif
+ }
+
+ ls->bind = 1;
+
+ continue;
+
+#if (NGX_HAVE_KEEPALIVE_TUNABLE)
+ invalid_so_keepalive:
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid so_keepalive value: \"%s\"",
+ &value[i].data[13]);
+ return NGX_CONF_ERROR;
+#endif
+ }
+
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the invalid \"%V\" parameter", &value[i]);
return NGX_CONF_ERROR;
@@ -494,7 +590,6 @@ ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_mail_core_srv_conf_t *cscf = conf;
- ngx_url_t u;
ngx_str_t *value;
value = cf->args->elts;
@@ -508,19 +603,9 @@ ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return NGX_CONF_OK;
}
- ngx_memzero(&u, sizeof(ngx_url_t));
-
- u.host = value[1];
- u.port = 53;
-
- if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V: %s", &u.host, u.err);
- return NGX_CONF_ERROR;
- }
-
- cscf->resolver = ngx_resolver_create(cf, &u.addrs[0]);
+ cscf->resolver = ngx_resolver_create(cf, &value[1], cf->args->nelts - 1);
if (cscf->resolver == NULL) {
- return NGX_CONF_OK;
+ return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
diff --git a/usr.sbin/nginx/src/os/unix/ngx_daemon.c b/usr.sbin/nginx/src/os/unix/ngx_daemon.c
index f18860bbe2f..ab672110838 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_daemon.c
+++ b/usr.sbin/nginx/src/os/unix/ngx_daemon.c
@@ -9,7 +9,8 @@
#include <ngx_core.h>
-ngx_int_t ngx_daemon(ngx_log_t *log)
+ngx_int_t
+ngx_daemon(ngx_log_t *log)
{
int fd;
diff --git a/usr.sbin/nginx/src/os/unix/ngx_darwin.h b/usr.sbin/nginx/src/os/unix/ngx_darwin.h
index b3aba906be7..4d01b26ea54 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_darwin.h
+++ b/usr.sbin/nginx/src/os/unix/ngx_darwin.h
@@ -9,6 +9,7 @@
#define _NGX_DARWIN_H_INCLUDED_
+void ngx_debug_init(void);
ngx_chain_t *ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in,
off_t limit);
@@ -16,5 +17,7 @@ extern int ngx_darwin_kern_osreldate;
extern int ngx_darwin_hw_ncpu;
extern u_long ngx_darwin_net_inet_tcp_sendspace;
+extern ngx_uint_t ngx_debug_malloc;
+
#endif /* _NGX_DARWIN_H_INCLUDED_ */
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 a24e43c2002..149778c29ad 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_darwin_config.h
+++ b/usr.sbin/nginx/src/os/unix/ngx_darwin_config.h
@@ -88,6 +88,7 @@
#define NGX_HAVE_OS_SPECIFIC_INIT 1
+#define NGX_HAVE_DEBUG_MALLOC 1
extern char **environ;
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 5c542cda818..e3cc5fe3eec 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_darwin_init.c
+++ b/usr.sbin/nginx/src/os/unix/ngx_darwin_init.c
@@ -15,6 +15,8 @@ int ngx_darwin_hw_ncpu;
int ngx_darwin_kern_ipc_somaxconn;
u_long ngx_darwin_net_inet_tcp_sendspace;
+ngx_uint_t ngx_debug_malloc;
+
static ngx_os_io_t ngx_darwin_io = {
ngx_unix_recv,
@@ -56,6 +58,34 @@ sysctl_t sysctls[] = {
};
+void
+ngx_debug_init()
+{
+#if (NGX_DEBUG_MALLOC)
+
+ /*
+ * MacOSX 10.6, 10.7: MallocScribble fills freed memory with 0x55
+ * and fills allocated memory with 0xAA.
+ * MacOSX 10.4, 10.5: MallocScribble fills freed memory with 0x55,
+ * MallocPreScribble fills allocated memory with 0xAA.
+ * MacOSX 10.3: MallocScribble fills freed memory with 0x55,
+ * and no way to fill allocated memory.
+ */
+
+ setenv("MallocScribble", "1", 0);
+
+ ngx_debug_malloc = 1;
+
+#else
+
+ if (getenv("MallocScribble")) {
+ ngx_debug_malloc = 1;
+ }
+
+#endif
+}
+
+
ngx_int_t
ngx_os_specific_init(ngx_log_t *log)
{
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 ec247d21bfe..078d10b2429 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
@@ -103,10 +103,8 @@ ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
prev = NULL;
iov = NULL;
- for (cl = in;
- cl && header.nelts < IOV_MAX && send < limit;
- cl = cl->next)
- {
+ for (cl = in; cl && send < limit; cl = cl->next) {
+
if (ngx_buf_special(cl->buf)) {
continue;
}
@@ -125,6 +123,10 @@ ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
iov->iov_len += (size_t) size;
} else {
+ if (header.nelts >= IOV_MAX) {
+ break;
+ }
+
iov = ngx_array_push(&header);
if (iov == NULL) {
return NGX_CHAIN_ERROR;
@@ -178,7 +180,7 @@ ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
prev = NULL;
iov = NULL;
- while (cl && header.nelts < IOV_MAX && send < limit) {
+ while (cl && send < limit) {
if (ngx_buf_special(cl->buf)) {
cl = cl->next;
@@ -199,6 +201,10 @@ ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
iov->iov_len += (size_t) size;
} else {
+ if (trailer.nelts >= IOV_MAX) {
+ break;
+ }
+
iov = ngx_array_push(&trailer);
if (iov == NULL) {
return NGX_CHAIN_ERROR;
diff --git a/usr.sbin/nginx/src/os/unix/ngx_errno.h b/usr.sbin/nginx/src/os/unix/ngx_errno.h
index 092d05a0b7c..78af40bfe50 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_errno.h
+++ b/usr.sbin/nginx/src/os/unix/ngx_errno.h
@@ -48,6 +48,11 @@ typedef int ngx_err_t;
#define NGX_EILSEQ EILSEQ
#define NGX_ENOMOREFILES 0
+#if (NGX_HAVE_OPENAT)
+#define NGX_EMLINK EMLINK
+#define NGX_ELOOP ELOOP
+#endif
+
#if (__hpux__)
#define NGX_EAGAIN EWOULDBLOCK
#else
diff --git a/usr.sbin/nginx/src/os/unix/ngx_files.h b/usr.sbin/nginx/src/os/unix/ngx_files.h
index 12988245a08..9c97e2bb789 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_files.h
+++ b/usr.sbin/nginx/src/os/unix/ngx_files.h
@@ -76,6 +76,27 @@ typedef struct {
#define NGX_FILE_APPEND O_WRONLY|O_APPEND
#define NGX_FILE_NONBLOCK O_NONBLOCK
+#if (NGX_HAVE_OPENAT)
+#define NGX_FILE_NOFOLLOW O_NOFOLLOW
+
+#if defined(O_DIRECTORY)
+#define NGX_FILE_DIRECTORY O_DIRECTORY
+#else
+#define NGX_FILE_DIRECTORY 0
+#endif
+
+#if defined(O_SEARCH)
+#define NGX_FILE_SEARCH O_SEARCH|NGX_FILE_DIRECTORY
+
+#elif defined(O_EXEC)
+#define NGX_FILE_SEARCH O_EXEC|NGX_FILE_DIRECTORY
+
+#else
+#define NGX_FILE_SEARCH O_RDONLY|NGX_FILE_DIRECTORY
+#endif
+
+#endif /* NGX_HAVE_OPENAT */
+
#define NGX_FILE_DEFAULT_ACCESS 0644
#define NGX_FILE_OWNER_ACCESS 0600
@@ -179,14 +200,25 @@ void ngx_close_file_mapping(ngx_file_mapping_t *fm);
#endif
-#define ngx_realpath(p, r) realpath((char *) p, (char *) r)
+#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)
#define ngx_getcwd_n "getcwd()"
#define ngx_path_separator(c) ((c) == '/')
+
+#if defined(PATH_MAX)
+
+#define NGX_HAVE_MAX_PATH 1
#define NGX_MAX_PATH PATH_MAX
+#else
+
+#define NGX_MAX_PATH 4096
+
+#endif
+
+
#define NGX_DIR_MASK_LEN 0
@@ -325,6 +357,23 @@ ngx_int_t ngx_directio_off(ngx_fd_t fd);
size_t ngx_fs_bsize(u_char *name);
+#if (NGX_HAVE_OPENAT)
+
+#define ngx_openat_file(fd, name, mode, create, access) \
+ openat(fd, (const char *) name, mode|create, access)
+
+#define ngx_openat_file_n "openat()"
+
+#define ngx_file_at_info(fd, name, sb, flag) \
+ fstatat(fd, (const char *) name, sb, flag)
+
+#define ngx_file_at_info_n "fstatat()"
+
+#define NGX_AT_FDCWD (ngx_fd_t) AT_FDCWD
+
+#endif
+
+
#define ngx_stderr STDERR_FILENO
#define ngx_set_stderr(fd) dup2(fd, STDERR_FILENO)
#define ngx_set_stderr_n "dup2(STDERR_FILENO)"
diff --git a/usr.sbin/nginx/src/os/unix/ngx_freebsd.h b/usr.sbin/nginx/src/os/unix/ngx_freebsd.h
index 95bf57a702f..4f93da55cd2 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_freebsd.h
+++ b/usr.sbin/nginx/src/os/unix/ngx_freebsd.h
@@ -9,6 +9,7 @@
#define _NGX_FREEBSD_H_INCLUDED_
+void ngx_debug_init(void);
ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in,
off_t limit);
@@ -18,7 +19,7 @@ extern u_long ngx_freebsd_net_inet_tcp_sendspace;
extern ngx_uint_t ngx_freebsd_sendfile_nbytes_bug;
extern ngx_uint_t ngx_freebsd_use_tcp_nopush;
-extern ngx_uint_t ngx_freebsd_debug_malloc;
+extern ngx_uint_t ngx_debug_malloc;
#endif /* _NGX_FREEBSD_H_INCLUDED_ */
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 f13793619b0..5b3ff278c01 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_freebsd_config.h
+++ b/usr.sbin/nginx/src/os/unix/ngx_freebsd_config.h
@@ -23,6 +23,7 @@
#include <grp.h>
#include <dirent.h>
#include <glob.h>
+#include <time.h>
#include <sys/param.h> /* ALIGN() */
#include <sys/mount.h> /* statfs() */
@@ -110,6 +111,7 @@ pid_t rfork_thread(int flags, void *stack, int (*func)(void *arg), void *arg);
#define NGX_HAVE_OS_SPECIFIC_INIT 1
+#define NGX_HAVE_DEBUG_MALLOC 1
extern char **environ;
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 02b3f2a7890..57af44a20cf 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_freebsd_init.c
+++ b/usr.sbin/nginx/src/os/unix/ngx_freebsd_init.c
@@ -23,7 +23,8 @@ int ngx_freebsd_machdep_hlt_logical_cpus;
ngx_uint_t ngx_freebsd_sendfile_nbytes_bug;
ngx_uint_t ngx_freebsd_use_tcp_nopush;
-ngx_uint_t ngx_freebsd_debug_malloc;
+
+ngx_uint_t ngx_debug_malloc;
static ngx_os_io_t ngx_freebsd_io = {
@@ -81,7 +82,7 @@ ngx_debug_init()
malloc_options = "J";
#endif
- ngx_freebsd_debug_malloc = 1;
+ ngx_debug_malloc = 1;
#else
char *mo;
@@ -89,7 +90,7 @@ ngx_debug_init()
mo = getenv("MALLOC_OPTIONS");
if (mo && ngx_strchr(mo, 'J')) {
- ngx_freebsd_debug_malloc = 1;
+ ngx_debug_malloc = 1;
}
#endif
}
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 9506b9de3ea..530ec4a53bb 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
@@ -11,14 +11,14 @@
/*
* The threads implementation uses the rfork(RFPROC|RFTHREAD|RFMEM) syscall
* to create threads. All threads use the stacks of the same size mmap()ed
- * below the main stack. Thus the current thread id is determinated via
+ * below the main stack. Thus the current thread id is determined via
* the stack pointer value.
*
* The mutex implementation uses the ngx_atomic_cmp_set() operation
* to acquire a mutex and the SysV semaphore to wait on a mutex and to wake up
* the waiting threads. The light mutex does not use semaphore, so after
* spinning in the lock the thread calls sched_yield(). However the light
- * mutecies are intended to be used with the "trylock" operation only.
+ * mutexes are intended to be used with the "trylock" operation only.
* The SysV semop() is a cheap syscall, particularly if it has little sembuf's
* and does not use SEM_UNDO.
*
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 26b326705c5..f58b5c20fe1 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
@@ -18,7 +18,7 @@
* as the 11 full 1460-bytes packets, then one incomplete 324-bytes packet,
* and then again the 11 full 1460-bytes packets.
*
- * Threfore we use the TCP_NOPUSH option (similar to Linux's TCP_CORK)
+ * Therefore we use the TCP_NOPUSH option (similar to Linux's TCP_CORK)
* to postpone the sending - it not only sends a header and the first part of
* the file in one packet, but also sends the file pages in the full packets.
*
@@ -107,10 +107,8 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
prev = NULL;
iov = NULL;
- for (cl = in;
- cl && header.nelts < IOV_MAX && send < limit;
- cl = cl->next)
- {
+ for (cl = in; cl && send < limit; cl = cl->next) {
+
if (ngx_buf_special(cl->buf)) {
continue;
}
@@ -129,6 +127,10 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
iov->iov_len += (size_t) size;
} else {
+ if (header.nelts >= IOV_MAX){
+ break;
+ }
+
iov = ngx_array_push(&header);
if (iov == NULL) {
return NGX_CHAIN_ERROR;
@@ -183,7 +185,7 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
prev = NULL;
iov = NULL;
- while (cl && header.nelts < IOV_MAX && send < limit) {
+ while (cl && send < limit) {
if (ngx_buf_special(cl->buf)) {
cl = cl->next;
@@ -204,6 +206,10 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
iov->iov_len += (size_t) size;
} else {
+ if (trailer.nelts >= IOV_MAX){
+ break;
+ }
+
iov = ngx_array_push(&trailer);
if (iov == NULL) {
return NGX_CHAIN_ERROR;
diff --git a/usr.sbin/nginx/src/os/unix/ngx_gcc_atomic_sparc64.h b/usr.sbin/nginx/src/os/unix/ngx_gcc_atomic_sparc64.h
index d26e1307cb5..a84db354482 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_gcc_atomic_sparc64.h
+++ b/usr.sbin/nginx/src/os/unix/ngx_gcc_atomic_sparc64.h
@@ -15,7 +15,7 @@
* r0 = [r1];
* }
*
- * so "r0 == r2" means that the operation was successfull.
+ * so "r0 == r2" means that the operation was successful.
*
*
* The "r" means the general register.
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 7cf4eac4179..2834032dea0 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_linux_config.h
+++ b/usr.sbin/nginx/src/os/unix/ngx_linux_config.h
@@ -109,6 +109,7 @@ typedef struct iocb ngx_aiocb_t;
#define NGX_HAVE_OS_SPECIFIC_INIT 1
+#define ngx_debug_init()
extern char **environ;
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 4f6fdf5876c..e8f3d5a894e 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
@@ -89,10 +89,8 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
/* create the iovec and coalesce the neighbouring bufs */
- for (cl = in;
- cl && header.nelts < IOV_MAX && send < limit;
- cl = cl->next)
- {
+ for (cl = in; cl && send < limit; cl = cl->next) {
+
if (ngx_buf_special(cl->buf)) {
continue;
}
@@ -132,6 +130,10 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
iov->iov_len += (size_t) size;
} else {
+ if (header.nelts >= IOV_MAX) {
+ break;
+ }
+
iov = ngx_array_push(&header);
if (iov == NULL) {
return NGX_CHAIN_ERROR;
diff --git a/usr.sbin/nginx/src/os/unix/ngx_os.h b/usr.sbin/nginx/src/os/unix/ngx_os.h
index 705bc5870c3..c646e2aa5a8 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_os.h
+++ b/usr.sbin/nginx/src/os/unix/ngx_os.h
@@ -32,7 +32,6 @@ typedef struct {
} ngx_os_io_t;
-void ngx_debug_init(void);
ngx_int_t ngx_os_init(ngx_log_t *log);
void ngx_os_status(ngx_log_t *log);
ngx_int_t ngx_os_specific_init(ngx_log_t *log);
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 263ee69f889..4d432a7e32e 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_posix_config.h
+++ b/usr.sbin/nginx/src/os/unix/ngx_posix_config.h
@@ -45,6 +45,7 @@
#include <grp.h>
#include <dirent.h>
#include <glob.h>
+#include <time.h>
#if (NGX_HAVE_SYS_PARAM_H)
#include <sys/param.h> /* statfs() */
#endif
@@ -126,6 +127,8 @@ typedef struct aiocb ngx_aiocb_t;
#define NGX_LISTEN_BACKLOG 511
+#define ngx_debug_init()
+
#if (__FreeBSD__) && (__FreeBSD_version < 400017)
diff --git a/usr.sbin/nginx/src/os/unix/ngx_process.c b/usr.sbin/nginx/src/os/unix/ngx_process.c
index f771b5aeda3..5713ca8e1b3 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_process.c
+++ b/usr.sbin/nginx/src/os/unix/ngx_process.c
@@ -23,6 +23,7 @@ typedef struct {
static void ngx_execute_proc(ngx_cycle_t *cycle, void *data);
static void ngx_signal_handler(int signo);
static void ngx_process_get_status(void);
+static void ngx_unlock_mutexes(ngx_pid_t pid);
int ngx_argc;
@@ -498,17 +499,6 @@ ngx_process_get_status(void)
}
- if (ngx_accept_mutex_ptr) {
-
- /*
- * unlock the accept mutex if the abnormally exited process
- * held it
- */
-
- ngx_atomic_cmp_set(ngx_accept_mutex_ptr, pid, 0);
- }
-
-
one = 1;
process = "unknown process";
@@ -546,6 +536,55 @@ ngx_process_get_status(void)
process, pid, WEXITSTATUS(status));
ngx_processes[i].respawn = 0;
}
+
+ ngx_unlock_mutexes(pid);
+ }
+}
+
+
+static void
+ngx_unlock_mutexes(ngx_pid_t pid)
+{
+ ngx_uint_t i;
+ ngx_shm_zone_t *shm_zone;
+ ngx_list_part_t *part;
+ ngx_slab_pool_t *sp;
+
+ /*
+ * unlock the accept mutex if the abnormally exited process
+ * held it
+ */
+
+ if (ngx_accept_mutex_ptr) {
+ (void) ngx_shmtx_force_unlock(&ngx_accept_mutex, pid);
+ }
+
+ /*
+ * unlock shared memory mutexes if held by the abnormally exited
+ * process
+ */
+
+ part = (ngx_list_part_t *) &ngx_cycle->shared_memory.part;
+ shm_zone = part->elts;
+
+ for (i = 0; /* void */ ; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+ part = part->next;
+ shm_zone = part->elts;
+ i = 0;
+ }
+
+ sp = (ngx_slab_pool_t *) shm_zone[i].shm.addr;
+
+ if (ngx_shmtx_force_unlock(&sp->mutex, pid)) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
+ "shared memory zone \"%V\" was locked by %P",
+ &shm_zone[i].shm.name, pid);
+ }
}
}
diff --git a/usr.sbin/nginx/src/os/unix/ngx_process.h b/usr.sbin/nginx/src/os/unix/ngx_process.h
index bd0252bd85f..7b5e8c0c25e 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_process.h
+++ b/usr.sbin/nginx/src/os/unix/ngx_process.h
@@ -9,6 +9,7 @@
#define _NGX_PROCESS_H_INCLUDED_
+#include <ngx_setaffinity.h>
#include <ngx_setproctitle.h>
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 7718483017d..b9d4c8c7ec5 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_process_cycle.c
+++ b/usr.sbin/nginx/src/os/unix/ngx_process_cycle.c
@@ -63,7 +63,7 @@ ngx_int_t ngx_threads_n;
#endif
-u_long cpu_affinity;
+uint64_t cpu_affinity;
static u_char master_process[] = "master process";
@@ -251,6 +251,10 @@ ngx_master_process_cycle(ngx_cycle_t *cycle)
ngx_start_worker_processes(cycle, ccf->worker_processes,
NGX_PROCESS_JUST_RESPAWN);
ngx_start_cache_manager_processes(cycle, 1);
+
+ /* allow new processes to start */
+ ngx_msleep(100);
+
live = 1;
ngx_signal_worker_processes(cycle,
ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
@@ -952,23 +956,10 @@ nochroot:
}
}
-#if (NGX_HAVE_SCHED_SETAFFINITY)
-
if (cpu_affinity) {
- ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0,
- "sched_setaffinity(0x%08Xl)", cpu_affinity);
-
- if (sched_setaffinity(0, sizeof(cpu_affinity),
- (cpu_set_t *) &cpu_affinity)
- == -1)
- {
- ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
- "sched_setaffinity(0x%08Xl) failed", cpu_affinity);
- }
+ ngx_setaffinity(cpu_affinity, cycle->log);
}
-#endif
-
#if (NGX_HAVE_PR_SET_DUMPABLE)
/* allow coredump after setuid() in Linux 2.4.x */
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 373c4027cb3..7b6badfa825 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_readv_chain.c
+++ b/usr.sbin/nginx/src/os/unix/ngx_readv_chain.c
@@ -71,6 +71,10 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain)
iov->iov_len += chain->buf->end - chain->buf->last;
} else {
+ if (vec.nelts >= IOV_MAX) {
+ break;
+ }
+
iov = ngx_array_push(&vec);
if (iov == NULL) {
return NGX_ERROR;
@@ -195,6 +199,10 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain)
iov->iov_len += chain->buf->end - chain->buf->last;
} else {
+ if (vec.nelts >= IOV_MAX) {
+ break;
+ }
+
iov = ngx_array_push(&vec);
if (iov == NULL) {
return NGX_ERROR;
diff --git a/usr.sbin/nginx/src/os/unix/ngx_setaffinity.c b/usr.sbin/nginx/src/os/unix/ngx_setaffinity.c
new file mode 100644
index 00000000000..8f6cf35948a
--- /dev/null
+++ b/usr.sbin/nginx/src/os/unix/ngx_setaffinity.c
@@ -0,0 +1,69 @@
+
+/*
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#if (NGX_HAVE_CPUSET_SETAFFINITY)
+
+#include <sys/cpuset.h>
+
+void
+ngx_setaffinity(uint64_t cpu_affinity, ngx_log_t *log)
+{
+ cpuset_t mask;
+ ngx_uint_t i;
+
+ ngx_log_error(NGX_LOG_NOTICE, log, 0,
+ "cpuset_setaffinity(0x%08Xl)", cpu_affinity);
+
+ CPU_ZERO(&mask);
+ i = 0;
+ do {
+ if (cpu_affinity & 1) {
+ CPU_SET(i, &mask);
+ }
+ i++;
+ cpu_affinity >>= 1;
+ } while (cpu_affinity);
+
+ if (cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1,
+ sizeof(cpuset_t), &mask) == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ "cpuset_setaffinity() failed");
+ }
+}
+
+#elif (NGX_HAVE_SCHED_SETAFFINITY)
+
+void
+ngx_setaffinity(uint64_t cpu_affinity, ngx_log_t *log)
+{
+ cpu_set_t mask;
+ ngx_uint_t i;
+
+ ngx_log_error(NGX_LOG_NOTICE, log, 0,
+ "sched_setaffinity(0x%08Xl)", cpu_affinity);
+
+ CPU_ZERO(&mask);
+ i = 0;
+ do {
+ if (cpu_affinity & 1) {
+ CPU_SET(i, &mask);
+ }
+ i++;
+ cpu_affinity >>= 1;
+ } while (cpu_affinity);
+
+ if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ "sched_setaffinity() failed");
+ }
+}
+
+#endif
diff --git a/usr.sbin/nginx/src/os/unix/ngx_setaffinity.h b/usr.sbin/nginx/src/os/unix/ngx_setaffinity.h
new file mode 100644
index 00000000000..33f5835dee6
--- /dev/null
+++ b/usr.sbin/nginx/src/os/unix/ngx_setaffinity.h
@@ -0,0 +1,23 @@
+
+/*
+ * Copyright (C) Nginx, Inc.
+ */
+
+#ifndef _NGX_SETAFFINITY_H_INCLUDED_
+#define _NGX_SETAFFINITY_H_INCLUDED_
+
+
+#if (NGX_HAVE_SCHED_SETAFFINITY || NGX_HAVE_CPUSET_SETAFFINITY)
+
+#define NGX_HAVE_CPU_AFFINITY 1
+
+void ngx_setaffinity(uint64_t cpu_affinity, ngx_log_t *log);
+
+#else
+
+#define ngx_setaffinity(cpu_affinity, log)
+
+#endif
+
+
+#endif /* _NGX_SETAFFINITY_H_INCLUDED_ */
diff --git a/usr.sbin/nginx/src/os/unix/ngx_setproctitle.c b/usr.sbin/nginx/src/os/unix/ngx_setproctitle.c
index a61fe1b9427..91afa519142 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_setproctitle.c
+++ b/usr.sbin/nginx/src/os/unix/ngx_setproctitle.c
@@ -21,7 +21,7 @@
* from argv[0] for our process title.
*
* The Solaris's standard /bin/ps does not show the changed process title.
- * You have to use "/usr/ucb/ps -w" instead. Besides, the UCB ps dos not
+ * You have to use "/usr/ucb/ps -w" instead. Besides, the UCB ps does not
* show a new title if its length less than the origin command line length.
* To avoid it we append to a new title the origin command line in the
* parenthesis.
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 278bfd29556..e664ba826c0 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_solaris_config.h
+++ b/usr.sbin/nginx/src/os/unix/ngx_solaris_config.h
@@ -29,6 +29,7 @@
#include <grp.h>
#include <dirent.h>
#include <glob.h>
+#include <time.h>
#include <sys/statvfs.h> /* statvfs() */
#include <sys/filio.h> /* FIONBIO */
@@ -99,6 +100,7 @@
#define NGX_HAVE_OS_SPECIFIC_INIT 1
+#define ngx_debug_init()
extern char **environ;
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 d68220dc32f..f800c15f5c9 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
@@ -74,7 +74,6 @@ ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
send = 0;
- complete = 0;
vec.elts = sfvs;
vec.size = sizeof(sendfilevec_t);
@@ -87,6 +86,7 @@ ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
fprev = 0;
sfv = NULL;
eintr = 0;
+ complete = 0;
sent = 0;
prev_send = send;
@@ -94,8 +94,8 @@ ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
/* create the sendfilevec and coalesce the neighbouring bufs */
- for (cl = in; cl && vec.nelts < IOV_MAX && send < limit; cl = cl->next)
- {
+ for (cl = in; cl && send < limit; cl = cl->next) {
+
if (ngx_buf_special(cl->buf)) {
continue;
}
@@ -113,6 +113,10 @@ ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
sfv->sfv_len += (size_t) size;
} else {
+ if (vec.nelts >= IOV_MAX) {
+ break;
+ }
+
sfv = ngx_array_push(&vec);
if (sfv == NULL) {
return NGX_CHAIN_ERROR;
@@ -147,6 +151,10 @@ ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
sfv->sfv_len += (size_t) size;
} else {
+ if (vec.nelts >= IOV_MAX) {
+ break;
+ }
+
sfv = ngx_array_push(&vec);
if (sfv == NULL) {
return NGX_CHAIN_ERROR;
diff --git a/usr.sbin/nginx/src/os/unix/ngx_writev_chain.c b/usr.sbin/nginx/src/os/unix/ngx_writev_chain.c
index 579fdecc897..805982d6558 100644
--- a/usr.sbin/nginx/src/os/unix/ngx_writev_chain.c
+++ b/usr.sbin/nginx/src/os/unix/ngx_writev_chain.c
@@ -54,7 +54,6 @@ ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
}
send = 0;
- complete = 0;
vec.elts = iovs;
vec.size = sizeof(struct iovec);
@@ -65,14 +64,15 @@ ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
prev = NULL;
iov = NULL;
eintr = 0;
+ complete = 0;
prev_send = send;
vec.nelts = 0;
/* create the iovec and coalesce the neighbouring bufs */
- for (cl = in; cl && vec.nelts < IOV_MAX && send < limit; cl = cl->next)
- {
+ for (cl = in; cl && send < limit; cl = cl->next) {
+
if (ngx_buf_special(cl->buf)) {
continue;
}
@@ -93,6 +93,10 @@ ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
iov->iov_len += size;
} else {
+ if (vec.nelts >= IOV_MAX) {
+ break;
+ }
+
iov = ngx_array_push(&vec);
if (iov == NULL) {
return NGX_CHAIN_ERROR;
diff --git a/usr.sbin/nginx/src/pcre/pcre_study.c b/usr.sbin/nginx/src/pcre/pcre_study.c
new file mode 100644
index 00000000000..61deb56f053
--- /dev/null
+++ b/usr.sbin/nginx/src/pcre/pcre_study.c
@@ -0,0 +1,1527 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Copyright (c) 1997-2012 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This module contains the external function pcre_study(), along with local
+supporting functions. */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre_internal.h"
+
+#define SET_BIT(c) start_bits[c/8] |= (1 << (c&7))
+
+/* Returns from set_start_bits() */
+
+enum { SSB_FAIL, SSB_DONE, SSB_CONTINUE, SSB_UNKNOWN };
+
+
+
+/*************************************************
+* Find the minimum subject length for a group *
+*************************************************/
+
+/* Scan a parenthesized group and compute the minimum length of subject that
+is needed to match it. This is a lower bound; it does not mean there is a
+string of that length that matches. In UTF8 mode, the result is in characters
+rather than bytes.
+
+Arguments:
+ code pointer to start of group (the bracket)
+ startcode pointer to start of the whole pattern
+ options the compiling options
+ int RECURSE depth
+
+Returns: the minimum length
+ -1 if \C in UTF-8 mode or (*ACCEPT) was encountered
+ -2 internal error (missing capturing bracket)
+ -3 internal error (opcode not listed)
+*/
+
+static int
+find_minlength(const pcre_uchar *code, const pcre_uchar *startcode, int options,
+ int recurse_depth)
+{
+int length = -1;
+/* PCRE_UTF16 has the same value as PCRE_UTF8. */
+BOOL utf = (options & PCRE_UTF8) != 0;
+BOOL had_recurse = FALSE;
+register int branchlength = 0;
+register pcre_uchar *cc = (pcre_uchar *)code + 1 + LINK_SIZE;
+
+if (*code == OP_CBRA || *code == OP_SCBRA ||
+ *code == OP_CBRAPOS || *code == OP_SCBRAPOS) cc += IMM2_SIZE;
+
+/* Scan along the opcodes for this branch. If we get to the end of the
+branch, check the length against that of the other branches. */
+
+for (;;)
+ {
+ int d, min;
+ pcre_uchar *cs, *ce;
+ register int op = *cc;
+
+ switch (op)
+ {
+ case OP_COND:
+ case OP_SCOND:
+
+ /* If there is only one branch in a condition, the implied branch has zero
+ length, so we don't add anything. This covers the DEFINE "condition"
+ automatically. */
+
+ cs = cc + GET(cc, 1);
+ if (*cs != OP_ALT)
+ {
+ cc = cs + 1 + LINK_SIZE;
+ break;
+ }
+
+ /* Otherwise we can fall through and treat it the same as any other
+ subpattern. */
+
+ case OP_CBRA:
+ case OP_SCBRA:
+ case OP_BRA:
+ case OP_SBRA:
+ case OP_CBRAPOS:
+ case OP_SCBRAPOS:
+ case OP_BRAPOS:
+ case OP_SBRAPOS:
+ case OP_ONCE:
+ case OP_ONCE_NC:
+ d = find_minlength(cc, startcode, options, recurse_depth);
+ if (d < 0) return d;
+ branchlength += d;
+ do cc += GET(cc, 1); while (*cc == OP_ALT);
+ cc += 1 + LINK_SIZE;
+ break;
+
+ /* ACCEPT makes things far too complicated; we have to give up. */
+
+ case OP_ACCEPT:
+ case OP_ASSERT_ACCEPT:
+ return -1;
+
+ /* Reached end of a branch; if it's a ket it is the end of a nested
+ call. If it's ALT it is an alternation in a nested call. If it is END it's
+ the end of the outer call. All can be handled by the same code. If an
+ ACCEPT was previously encountered, use the length that was in force at that
+ time, and pass back the shortest ACCEPT length. */
+
+ case OP_ALT:
+ case OP_KET:
+ case OP_KETRMAX:
+ case OP_KETRMIN:
+ case OP_KETRPOS:
+ case OP_END:
+ if (length < 0 || (!had_recurse && branchlength < length))
+ length = branchlength;
+ if (op != OP_ALT) return length;
+ cc += 1 + LINK_SIZE;
+ branchlength = 0;
+ had_recurse = FALSE;
+ break;
+
+ /* Skip over assertive subpatterns */
+
+ case OP_ASSERT:
+ case OP_ASSERT_NOT:
+ case OP_ASSERTBACK:
+ case OP_ASSERTBACK_NOT:
+ do cc += GET(cc, 1); while (*cc == OP_ALT);
+ /* Fall through */
+
+ /* Skip over things that don't match chars */
+
+ case OP_REVERSE:
+ case OP_CREF:
+ case OP_NCREF:
+ case OP_RREF:
+ case OP_NRREF:
+ case OP_DEF:
+ case OP_CALLOUT:
+ case OP_SOD:
+ case OP_SOM:
+ case OP_EOD:
+ case OP_EODN:
+ case OP_CIRC:
+ case OP_CIRCM:
+ case OP_DOLL:
+ case OP_DOLLM:
+ case OP_NOT_WORD_BOUNDARY:
+ case OP_WORD_BOUNDARY:
+ cc += PRIV(OP_lengths)[*cc];
+ break;
+
+ /* Skip over a subpattern that has a {0} or {0,x} quantifier */
+
+ case OP_BRAZERO:
+ case OP_BRAMINZERO:
+ case OP_BRAPOSZERO:
+ case OP_SKIPZERO:
+ cc += PRIV(OP_lengths)[*cc];
+ do cc += GET(cc, 1); while (*cc == OP_ALT);
+ cc += 1 + LINK_SIZE;
+ break;
+
+ /* Handle literal characters and + repetitions */
+
+ case OP_CHAR:
+ case OP_CHARI:
+ case OP_NOT:
+ case OP_NOTI:
+ case OP_PLUS:
+ case OP_PLUSI:
+ case OP_MINPLUS:
+ case OP_MINPLUSI:
+ case OP_POSPLUS:
+ case OP_POSPLUSI:
+ case OP_NOTPLUS:
+ case OP_NOTPLUSI:
+ case OP_NOTMINPLUS:
+ case OP_NOTMINPLUSI:
+ case OP_NOTPOSPLUS:
+ case OP_NOTPOSPLUSI:
+ branchlength++;
+ cc += 2;
+#ifdef SUPPORT_UTF
+ if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+ break;
+
+ case OP_TYPEPLUS:
+ case OP_TYPEMINPLUS:
+ case OP_TYPEPOSPLUS:
+ branchlength++;
+ cc += (cc[1] == OP_PROP || cc[1] == OP_NOTPROP)? 4 : 2;
+ break;
+
+ /* Handle exact repetitions. The count is already in characters, but we
+ need to skip over a multibyte character in UTF8 mode. */
+
+ case OP_EXACT:
+ case OP_EXACTI:
+ case OP_NOTEXACT:
+ case OP_NOTEXACTI:
+ branchlength += GET2(cc,1);
+ cc += 2 + IMM2_SIZE;
+#ifdef SUPPORT_UTF
+ if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+ break;
+
+ case OP_TYPEEXACT:
+ branchlength += GET2(cc,1);
+ cc += 2 + IMM2_SIZE + ((cc[1 + IMM2_SIZE] == OP_PROP
+ || cc[1 + IMM2_SIZE] == OP_NOTPROP)? 2 : 0);
+ break;
+
+ /* Handle single-char non-literal matchers */
+
+ case OP_PROP:
+ case OP_NOTPROP:
+ cc += 2;
+ /* Fall through */
+
+ case OP_NOT_DIGIT:
+ case OP_DIGIT:
+ case OP_NOT_WHITESPACE:
+ case OP_WHITESPACE:
+ case OP_NOT_WORDCHAR:
+ case OP_WORDCHAR:
+ case OP_ANY:
+ case OP_ALLANY:
+ case OP_EXTUNI:
+ case OP_HSPACE:
+ case OP_NOT_HSPACE:
+ case OP_VSPACE:
+ case OP_NOT_VSPACE:
+ branchlength++;
+ cc++;
+ break;
+
+ /* "Any newline" might match two characters, but it also might match just
+ one. */
+
+ case OP_ANYNL:
+ branchlength += 1;
+ cc++;
+ break;
+
+ /* The single-byte matcher means we can't proceed in UTF-8 mode. (In
+ non-UTF-8 mode \C will actually be turned into OP_ALLANY, so won't ever
+ appear, but leave the code, just in case.) */
+
+ case OP_ANYBYTE:
+#ifdef SUPPORT_UTF
+ if (utf) return -1;
+#endif
+ branchlength++;
+ cc++;
+ break;
+
+ /* For repeated character types, we have to test for \p and \P, which have
+ an extra two bytes of parameters. */
+
+ case OP_TYPESTAR:
+ case OP_TYPEMINSTAR:
+ case OP_TYPEQUERY:
+ case OP_TYPEMINQUERY:
+ case OP_TYPEPOSSTAR:
+ case OP_TYPEPOSQUERY:
+ if (cc[1] == OP_PROP || cc[1] == OP_NOTPROP) cc += 2;
+ cc += PRIV(OP_lengths)[op];
+ break;
+
+ case OP_TYPEUPTO:
+ case OP_TYPEMINUPTO:
+ case OP_TYPEPOSUPTO:
+ if (cc[1 + IMM2_SIZE] == OP_PROP
+ || cc[1 + IMM2_SIZE] == OP_NOTPROP) cc += 2;
+ cc += PRIV(OP_lengths)[op];
+ break;
+
+ /* Check a class for variable quantification */
+
+#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
+ case OP_XCLASS:
+ cc += GET(cc, 1) - PRIV(OP_lengths)[OP_CLASS];
+ /* Fall through */
+#endif
+
+ case OP_CLASS:
+ case OP_NCLASS:
+ cc += PRIV(OP_lengths)[OP_CLASS];
+
+ switch (*cc)
+ {
+ case OP_CRPLUS:
+ case OP_CRMINPLUS:
+ branchlength++;
+ /* Fall through */
+
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ cc++;
+ break;
+
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ branchlength += GET2(cc,1);
+ cc += 1 + 2 * IMM2_SIZE;
+ break;
+
+ default:
+ branchlength++;
+ break;
+ }
+ break;
+
+ /* Backreferences and subroutine calls are treated in the same way: we find
+ the minimum length for the subpattern. A recursion, however, causes an
+ a flag to be set that causes the length of this branch to be ignored. The
+ logic is that a recursion can only make sense if there is another
+ alternation that stops the recursing. That will provide the minimum length
+ (when no recursion happens). A backreference within the group that it is
+ referencing behaves in the same way.
+
+ If PCRE_JAVASCRIPT_COMPAT is set, a backreference to an unset bracket
+ matches an empty string (by default it causes a matching failure), so in
+ that case we must set the minimum length to zero. */
+
+ case OP_REF:
+ case OP_REFI:
+ if ((options & PCRE_JAVASCRIPT_COMPAT) == 0)
+ {
+ ce = cs = (pcre_uchar *)PRIV(find_bracket)(startcode, utf, GET2(cc, 1));
+ if (cs == NULL) return -2;
+ do ce += GET(ce, 1); while (*ce == OP_ALT);
+ if (cc > cs && cc < ce)
+ {
+ d = 0;
+ had_recurse = TRUE;
+ }
+ else
+ {
+ d = find_minlength(cs, startcode, options, recurse_depth);
+ }
+ }
+ else d = 0;
+ cc += 1 + IMM2_SIZE;
+
+ /* Handle repeated back references */
+
+ switch (*cc)
+ {
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ min = 0;
+ cc++;
+ break;
+
+ case OP_CRPLUS:
+ case OP_CRMINPLUS:
+ min = 1;
+ cc++;
+ break;
+
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ min = GET2(cc, 1);
+ cc += 1 + 2 * IMM2_SIZE;
+ break;
+
+ default:
+ min = 1;
+ break;
+ }
+
+ branchlength += min * d;
+ break;
+
+ /* We can easily detect direct recursion, but not mutual recursion. This is
+ caught by a recursion depth count. */
+
+ case OP_RECURSE:
+ cs = ce = (pcre_uchar *)startcode + GET(cc, 1);
+ do ce += GET(ce, 1); while (*ce == OP_ALT);
+ if ((cc > cs && cc < ce) || recurse_depth > 10)
+ had_recurse = TRUE;
+ else
+ {
+ branchlength += find_minlength(cs, startcode, options, recurse_depth + 1);
+ }
+ cc += 1 + LINK_SIZE;
+ break;
+
+ /* Anything else does not or need not match a character. We can get the
+ item's length from the table, but for those that can match zero occurrences
+ of a character, we must take special action for UTF-8 characters. As it
+ happens, the "NOT" versions of these opcodes are used at present only for
+ ASCII characters, so they could be omitted from this list. However, in
+ future that may change, so we include them here so as not to leave a
+ gotcha for a future maintainer. */
+
+ case OP_UPTO:
+ case OP_UPTOI:
+ case OP_NOTUPTO:
+ case OP_NOTUPTOI:
+ case OP_MINUPTO:
+ case OP_MINUPTOI:
+ case OP_NOTMINUPTO:
+ case OP_NOTMINUPTOI:
+ case OP_POSUPTO:
+ case OP_POSUPTOI:
+ case OP_NOTPOSUPTO:
+ case OP_NOTPOSUPTOI:
+
+ case OP_STAR:
+ case OP_STARI:
+ case OP_NOTSTAR:
+ case OP_NOTSTARI:
+ case OP_MINSTAR:
+ case OP_MINSTARI:
+ case OP_NOTMINSTAR:
+ case OP_NOTMINSTARI:
+ case OP_POSSTAR:
+ case OP_POSSTARI:
+ case OP_NOTPOSSTAR:
+ case OP_NOTPOSSTARI:
+
+ case OP_QUERY:
+ case OP_QUERYI:
+ case OP_NOTQUERY:
+ case OP_NOTQUERYI:
+ case OP_MINQUERY:
+ case OP_MINQUERYI:
+ case OP_NOTMINQUERY:
+ case OP_NOTMINQUERYI:
+ case OP_POSQUERY:
+ case OP_POSQUERYI:
+ case OP_NOTPOSQUERY:
+ case OP_NOTPOSQUERYI:
+
+ cc += PRIV(OP_lengths)[op];
+#ifdef SUPPORT_UTF
+ if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+ break;
+
+ /* Skip these, but we need to add in the name length. */
+
+ case OP_MARK:
+ case OP_PRUNE_ARG:
+ case OP_SKIP_ARG:
+ case OP_THEN_ARG:
+ cc += PRIV(OP_lengths)[op] + cc[1];
+ break;
+
+ /* The remaining opcodes are just skipped over. */
+
+ case OP_CLOSE:
+ case OP_COMMIT:
+ case OP_FAIL:
+ case OP_PRUNE:
+ case OP_SET_SOM:
+ case OP_SKIP:
+ case OP_THEN:
+ cc += PRIV(OP_lengths)[op];
+ break;
+
+ /* This should not occur: we list all opcodes explicitly so that when
+ new ones get added they are properly considered. */
+
+ default:
+ return -3;
+ }
+ }
+/* Control never gets here */
+}
+
+
+
+/*************************************************
+* Set a bit and maybe its alternate case *
+*************************************************/
+
+/* Given a character, set its first byte's bit in the table, and also the
+corresponding bit for the other version of a letter if we are caseless. In
+UTF-8 mode, for characters greater than 127, we can only do the caseless thing
+when Unicode property support is available.
+
+Arguments:
+ start_bits points to the bit map
+ p points to the character
+ caseless the caseless flag
+ cd the block with char table pointers
+ utf TRUE for UTF-8 / UTF-16 mode
+
+Returns: pointer after the character
+*/
+
+static const pcre_uchar *
+set_table_bit(pcre_uint8 *start_bits, const pcre_uchar *p, BOOL caseless,
+ compile_data *cd, BOOL utf)
+{
+unsigned int c = *p;
+
+#ifdef COMPILE_PCRE8
+SET_BIT(c);
+
+#ifdef SUPPORT_UTF
+if (utf && c > 127)
+ {
+ GETCHARINC(c, p);
+#ifdef SUPPORT_UCP
+ if (caseless)
+ {
+ pcre_uchar buff[6];
+ c = UCD_OTHERCASE(c);
+ (void)PRIV(ord2utf)(c, buff);
+ SET_BIT(buff[0]);
+ }
+#endif
+ return p;
+ }
+#endif
+
+/* Not UTF-8 mode, or character is less than 127. */
+
+if (caseless && (cd->ctypes[c] & ctype_letter) != 0) SET_BIT(cd->fcc[c]);
+return p + 1;
+#endif
+
+#ifdef COMPILE_PCRE16
+if (c > 0xff)
+ {
+ c = 0xff;
+ caseless = FALSE;
+ }
+SET_BIT(c);
+
+#ifdef SUPPORT_UTF
+if (utf && c > 127)
+ {
+ GETCHARINC(c, p);
+#ifdef SUPPORT_UCP
+ if (caseless)
+ {
+ c = UCD_OTHERCASE(c);
+ if (c > 0xff)
+ c = 0xff;
+ SET_BIT(c);
+ }
+#endif
+ return p;
+ }
+#endif
+
+if (caseless && (cd->ctypes[c] & ctype_letter) != 0) SET_BIT(cd->fcc[c]);
+return p + 1;
+#endif
+}
+
+
+
+/*************************************************
+* Set bits for a positive character type *
+*************************************************/
+
+/* This function sets starting bits for a character type. In UTF-8 mode, we can
+only do a direct setting for bytes less than 128, as otherwise there can be
+confusion with bytes in the middle of UTF-8 characters. In a "traditional"
+environment, the tables will only recognize ASCII characters anyway, but in at
+least one Windows environment, some higher bytes bits were set in the tables.
+So we deal with that case by considering the UTF-8 encoding.
+
+Arguments:
+ start_bits the starting bitmap
+ cbit type the type of character wanted
+ table_limit 32 for non-UTF-8; 16 for UTF-8
+ cd the block with char table pointers
+
+Returns: nothing
+*/
+
+static void
+set_type_bits(pcre_uint8 *start_bits, int cbit_type, int table_limit,
+ compile_data *cd)
+{
+register int c;
+for (c = 0; c < table_limit; c++) start_bits[c] |= cd->cbits[c+cbit_type];
+#if defined SUPPORT_UTF && defined COMPILE_PCRE8
+if (table_limit == 32) return;
+for (c = 128; c < 256; c++)
+ {
+ if ((cd->cbits[c/8] & (1 << (c&7))) != 0)
+ {
+ pcre_uchar buff[6];
+ (void)PRIV(ord2utf)(c, buff);
+ SET_BIT(buff[0]);
+ }
+ }
+#endif
+}
+
+
+/*************************************************
+* Set bits for a negative character type *
+*************************************************/
+
+/* This function sets starting bits for a negative character type such as \D.
+In UTF-8 mode, we can only do a direct setting for bytes less than 128, as
+otherwise there can be confusion with bytes in the middle of UTF-8 characters.
+Unlike in the positive case, where we can set appropriate starting bits for
+specific high-valued UTF-8 characters, in this case we have to set the bits for
+all high-valued characters. The lowest is 0xc2, but we overkill by starting at
+0xc0 (192) for simplicity.
+
+Arguments:
+ start_bits the starting bitmap
+ cbit type the type of character wanted
+ table_limit 32 for non-UTF-8; 16 for UTF-8
+ cd the block with char table pointers
+
+Returns: nothing
+*/
+
+static void
+set_nottype_bits(pcre_uint8 *start_bits, int cbit_type, int table_limit,
+ compile_data *cd)
+{
+register int c;
+for (c = 0; c < table_limit; c++) start_bits[c] |= ~cd->cbits[c+cbit_type];
+#if defined SUPPORT_UTF && defined COMPILE_PCRE8
+if (table_limit != 32) for (c = 24; c < 32; c++) start_bits[c] = 0xff;
+#endif
+}
+
+
+
+/*************************************************
+* Create bitmap of starting bytes *
+*************************************************/
+
+/* This function scans a compiled unanchored expression recursively and
+attempts to build a bitmap of the set of possible starting bytes. As time goes
+by, we may be able to get more clever at doing this. The SSB_CONTINUE return is
+useful for parenthesized groups in patterns such as (a*)b where the group
+provides some optional starting bytes but scanning must continue at the outer
+level to find at least one mandatory byte. At the outermost level, this
+function fails unless the result is SSB_DONE.
+
+Arguments:
+ code points to an expression
+ start_bits points to a 32-byte table, initialized to 0
+ utf TRUE if in UTF-8 / UTF-16 mode
+ cd the block with char table pointers
+
+Returns: SSB_FAIL => Failed to find any starting bytes
+ SSB_DONE => Found mandatory starting bytes
+ SSB_CONTINUE => Found optional starting bytes
+ SSB_UNKNOWN => Hit an unrecognized opcode
+*/
+
+static int
+set_start_bits(const pcre_uchar *code, pcre_uint8 *start_bits, BOOL utf,
+ compile_data *cd)
+{
+register int c;
+int yield = SSB_DONE;
+#if defined SUPPORT_UTF && defined COMPILE_PCRE8
+int table_limit = utf? 16:32;
+#else
+int table_limit = 32;
+#endif
+
+#if 0
+/* ========================================================================= */
+/* The following comment and code was inserted in January 1999. In May 2006,
+when it was observed to cause compiler warnings about unused values, I took it
+out again. If anybody is still using OS/2, they will have to put it back
+manually. */
+
+/* This next statement and the later reference to dummy are here in order to
+trick the optimizer of the IBM C compiler for OS/2 into generating correct
+code. Apparently IBM isn't going to fix the problem, and we would rather not
+disable optimization (in this module it actually makes a big difference, and
+the pcre module can use all the optimization it can get). */
+
+volatile int dummy;
+/* ========================================================================= */
+#endif
+
+do
+ {
+ BOOL try_next = TRUE;
+ const pcre_uchar *tcode = code + 1 + LINK_SIZE;
+
+ if (*code == OP_CBRA || *code == OP_SCBRA ||
+ *code == OP_CBRAPOS || *code == OP_SCBRAPOS) tcode += IMM2_SIZE;
+
+ while (try_next) /* Loop for items in this branch */
+ {
+ int rc;
+
+ switch(*tcode)
+ {
+ /* If we reach something we don't understand, it means a new opcode has
+ been created that hasn't been added to this code. Hopefully this problem
+ will be discovered during testing. */
+
+ default:
+ return SSB_UNKNOWN;
+
+ /* Fail for a valid opcode that implies no starting bits. */
+
+ case OP_ACCEPT:
+ case OP_ASSERT_ACCEPT:
+ case OP_ALLANY:
+ case OP_ANY:
+ case OP_ANYBYTE:
+ case OP_CIRC:
+ case OP_CIRCM:
+ case OP_CLOSE:
+ case OP_COMMIT:
+ case OP_COND:
+ case OP_CREF:
+ case OP_DEF:
+ case OP_DOLL:
+ case OP_DOLLM:
+ case OP_END:
+ case OP_EOD:
+ case OP_EODN:
+ case OP_EXTUNI:
+ case OP_FAIL:
+ case OP_MARK:
+ case OP_NCREF:
+ case OP_NOT:
+ case OP_NOTEXACT:
+ case OP_NOTEXACTI:
+ case OP_NOTI:
+ case OP_NOTMINPLUS:
+ case OP_NOTMINPLUSI:
+ case OP_NOTMINQUERY:
+ case OP_NOTMINQUERYI:
+ case OP_NOTMINSTAR:
+ case OP_NOTMINSTARI:
+ case OP_NOTMINUPTO:
+ case OP_NOTMINUPTOI:
+ case OP_NOTPLUS:
+ case OP_NOTPLUSI:
+ case OP_NOTPOSPLUS:
+ case OP_NOTPOSPLUSI:
+ case OP_NOTPOSQUERY:
+ case OP_NOTPOSQUERYI:
+ case OP_NOTPOSSTAR:
+ case OP_NOTPOSSTARI:
+ case OP_NOTPOSUPTO:
+ case OP_NOTPOSUPTOI:
+ case OP_NOTPROP:
+ case OP_NOTQUERY:
+ case OP_NOTQUERYI:
+ case OP_NOTSTAR:
+ case OP_NOTSTARI:
+ case OP_NOTUPTO:
+ case OP_NOTUPTOI:
+ case OP_NOT_HSPACE:
+ case OP_NOT_VSPACE:
+ case OP_NRREF:
+ case OP_PROP:
+ case OP_PRUNE:
+ case OP_PRUNE_ARG:
+ case OP_RECURSE:
+ case OP_REF:
+ case OP_REFI:
+ case OP_REVERSE:
+ case OP_RREF:
+ case OP_SCOND:
+ case OP_SET_SOM:
+ case OP_SKIP:
+ case OP_SKIP_ARG:
+ case OP_SOD:
+ case OP_SOM:
+ case OP_THEN:
+ case OP_THEN_ARG:
+#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
+ case OP_XCLASS:
+#endif
+ return SSB_FAIL;
+
+ /* We can ignore word boundary tests. */
+
+ case OP_WORD_BOUNDARY:
+ case OP_NOT_WORD_BOUNDARY:
+ tcode++;
+ break;
+
+ /* If we hit a bracket or a positive lookahead assertion, recurse to set
+ bits from within the subpattern. If it can't find anything, we have to
+ give up. If it finds some mandatory character(s), we are done for this
+ branch. Otherwise, carry on scanning after the subpattern. */
+
+ case OP_BRA:
+ case OP_SBRA:
+ case OP_CBRA:
+ case OP_SCBRA:
+ case OP_BRAPOS:
+ case OP_SBRAPOS:
+ case OP_CBRAPOS:
+ case OP_SCBRAPOS:
+ case OP_ONCE:
+ case OP_ONCE_NC:
+ case OP_ASSERT:
+ rc = set_start_bits(tcode, start_bits, utf, cd);
+ if (rc == SSB_FAIL || rc == SSB_UNKNOWN) return rc;
+ if (rc == SSB_DONE) try_next = FALSE; else
+ {
+ do tcode += GET(tcode, 1); while (*tcode == OP_ALT);
+ tcode += 1 + LINK_SIZE;
+ }
+ break;
+
+ /* If we hit ALT or KET, it means we haven't found anything mandatory in
+ this branch, though we might have found something optional. For ALT, we
+ continue with the next alternative, but we have to arrange that the final
+ result from subpattern is SSB_CONTINUE rather than SSB_DONE. For KET,
+ return SSB_CONTINUE: if this is the top level, that indicates failure,
+ but after a nested subpattern, it causes scanning to continue. */
+
+ case OP_ALT:
+ yield = SSB_CONTINUE;
+ try_next = FALSE;
+ break;
+
+ case OP_KET:
+ case OP_KETRMAX:
+ case OP_KETRMIN:
+ case OP_KETRPOS:
+ return SSB_CONTINUE;
+
+ /* Skip over callout */
+
+ case OP_CALLOUT:
+ tcode += 2 + 2*LINK_SIZE;
+ break;
+
+ /* Skip over lookbehind and negative lookahead assertions */
+
+ case OP_ASSERT_NOT:
+ case OP_ASSERTBACK:
+ case OP_ASSERTBACK_NOT:
+ do tcode += GET(tcode, 1); while (*tcode == OP_ALT);
+ tcode += 1 + LINK_SIZE;
+ break;
+
+ /* BRAZERO does the bracket, but carries on. */
+
+ case OP_BRAZERO:
+ case OP_BRAMINZERO:
+ case OP_BRAPOSZERO:
+ rc = set_start_bits(++tcode, start_bits, utf, cd);
+ if (rc == SSB_FAIL || rc == SSB_UNKNOWN) return rc;
+/* =========================================================================
+ See the comment at the head of this function concerning the next line,
+ which was an old fudge for the benefit of OS/2.
+ dummy = 1;
+ ========================================================================= */
+ do tcode += GET(tcode,1); while (*tcode == OP_ALT);
+ tcode += 1 + LINK_SIZE;
+ break;
+
+ /* SKIPZERO skips the bracket. */
+
+ case OP_SKIPZERO:
+ tcode++;
+ do tcode += GET(tcode,1); while (*tcode == OP_ALT);
+ tcode += 1 + LINK_SIZE;
+ break;
+
+ /* Single-char * or ? sets the bit and tries the next item */
+
+ case OP_STAR:
+ case OP_MINSTAR:
+ case OP_POSSTAR:
+ case OP_QUERY:
+ case OP_MINQUERY:
+ case OP_POSQUERY:
+ tcode = set_table_bit(start_bits, tcode + 1, FALSE, cd, utf);
+ break;
+
+ case OP_STARI:
+ case OP_MINSTARI:
+ case OP_POSSTARI:
+ case OP_QUERYI:
+ case OP_MINQUERYI:
+ case OP_POSQUERYI:
+ tcode = set_table_bit(start_bits, tcode + 1, TRUE, cd, utf);
+ break;
+
+ /* Single-char upto sets the bit and tries the next */
+
+ case OP_UPTO:
+ case OP_MINUPTO:
+ case OP_POSUPTO:
+ tcode = set_table_bit(start_bits, tcode + 1 + IMM2_SIZE, FALSE, cd, utf);
+ break;
+
+ case OP_UPTOI:
+ case OP_MINUPTOI:
+ case OP_POSUPTOI:
+ tcode = set_table_bit(start_bits, tcode + 1 + IMM2_SIZE, TRUE, cd, utf);
+ break;
+
+ /* At least one single char sets the bit and stops */
+
+ case OP_EXACT:
+ tcode += IMM2_SIZE;
+ /* Fall through */
+ case OP_CHAR:
+ case OP_PLUS:
+ case OP_MINPLUS:
+ case OP_POSPLUS:
+ (void)set_table_bit(start_bits, tcode + 1, FALSE, cd, utf);
+ try_next = FALSE;
+ break;
+
+ case OP_EXACTI:
+ tcode += IMM2_SIZE;
+ /* Fall through */
+ case OP_CHARI:
+ case OP_PLUSI:
+ case OP_MINPLUSI:
+ case OP_POSPLUSI:
+ (void)set_table_bit(start_bits, tcode + 1, TRUE, cd, utf);
+ try_next = FALSE;
+ break;
+
+ /* Special spacing and line-terminating items. These recognize specific
+ lists of characters. The difference between VSPACE and ANYNL is that the
+ latter can match the two-character CRLF sequence, but that is not
+ relevant for finding the first character, so their code here is
+ identical. */
+
+ case OP_HSPACE:
+ SET_BIT(0x09);
+ SET_BIT(0x20);
+#ifdef SUPPORT_UTF
+ if (utf)
+ {
+#ifdef COMPILE_PCRE8
+ SET_BIT(0xC2); /* For U+00A0 */
+ SET_BIT(0xE1); /* For U+1680, U+180E */
+ SET_BIT(0xE2); /* For U+2000 - U+200A, U+202F, U+205F */
+ SET_BIT(0xE3); /* For U+3000 */
+#endif
+#ifdef COMPILE_PCRE16
+ SET_BIT(0xA0);
+ SET_BIT(0xFF); /* For characters > 255 */
+#endif
+ }
+ else
+#endif /* SUPPORT_UTF */
+ {
+ SET_BIT(0xA0);
+#ifdef COMPILE_PCRE16
+ SET_BIT(0xFF); /* For characters > 255 */
+#endif
+ }
+ try_next = FALSE;
+ break;
+
+ case OP_ANYNL:
+ case OP_VSPACE:
+ SET_BIT(0x0A);
+ SET_BIT(0x0B);
+ SET_BIT(0x0C);
+ SET_BIT(0x0D);
+#ifdef SUPPORT_UTF
+ if (utf)
+ {
+#ifdef COMPILE_PCRE8
+ SET_BIT(0xC2); /* For U+0085 */
+ SET_BIT(0xE2); /* For U+2028, U+2029 */
+#endif
+#ifdef COMPILE_PCRE16
+ SET_BIT(0x85);
+ SET_BIT(0xFF); /* For characters > 255 */
+#endif
+ }
+ else
+#endif /* SUPPORT_UTF */
+ {
+ SET_BIT(0x85);
+#ifdef COMPILE_PCRE16
+ SET_BIT(0xFF); /* For characters > 255 */
+#endif
+ }
+ try_next = FALSE;
+ break;
+
+ /* Single character types set the bits and stop. Note that if PCRE_UCP
+ is set, we do not see these op codes because \d etc are converted to
+ properties. Therefore, these apply in the case when only characters less
+ than 256 are recognized to match the types. */
+
+ case OP_NOT_DIGIT:
+ set_nottype_bits(start_bits, cbit_digit, table_limit, cd);
+ try_next = FALSE;
+ break;
+
+ case OP_DIGIT:
+ set_type_bits(start_bits, cbit_digit, table_limit, cd);
+ try_next = FALSE;
+ break;
+
+ /* The cbit_space table has vertical tab as whitespace; we have to
+ ensure it is set as not whitespace. */
+
+ case OP_NOT_WHITESPACE:
+ set_nottype_bits(start_bits, cbit_space, table_limit, cd);
+ start_bits[1] |= 0x08;
+ try_next = FALSE;
+ break;
+
+ /* The cbit_space table has vertical tab as whitespace; we have to
+ not set it from the table. */
+
+ case OP_WHITESPACE:
+ c = start_bits[1]; /* Save in case it was already set */
+ set_type_bits(start_bits, cbit_space, table_limit, cd);
+ start_bits[1] = (start_bits[1] & ~0x08) | c;
+ try_next = FALSE;
+ break;
+
+ case OP_NOT_WORDCHAR:
+ set_nottype_bits(start_bits, cbit_word, table_limit, cd);
+ try_next = FALSE;
+ break;
+
+ case OP_WORDCHAR:
+ set_type_bits(start_bits, cbit_word, table_limit, cd);
+ try_next = FALSE;
+ break;
+
+ /* One or more character type fudges the pointer and restarts, knowing
+ it will hit a single character type and stop there. */
+
+ case OP_TYPEPLUS:
+ case OP_TYPEMINPLUS:
+ case OP_TYPEPOSPLUS:
+ tcode++;
+ break;
+
+ case OP_TYPEEXACT:
+ tcode += 1 + IMM2_SIZE;
+ break;
+
+ /* Zero or more repeats of character types set the bits and then
+ try again. */
+
+ case OP_TYPEUPTO:
+ case OP_TYPEMINUPTO:
+ case OP_TYPEPOSUPTO:
+ tcode += IMM2_SIZE; /* Fall through */
+
+ case OP_TYPESTAR:
+ case OP_TYPEMINSTAR:
+ case OP_TYPEPOSSTAR:
+ case OP_TYPEQUERY:
+ case OP_TYPEMINQUERY:
+ case OP_TYPEPOSQUERY:
+ switch(tcode[1])
+ {
+ default:
+ case OP_ANY:
+ case OP_ALLANY:
+ return SSB_FAIL;
+
+ case OP_HSPACE:
+ SET_BIT(0x09);
+ SET_BIT(0x20);
+#ifdef COMPILE_PCRE8
+ if (utf)
+ {
+#ifdef COMPILE_PCRE8
+ SET_BIT(0xC2); /* For U+00A0 */
+ SET_BIT(0xE1); /* For U+1680, U+180E */
+ SET_BIT(0xE2); /* For U+2000 - U+200A, U+202F, U+205F */
+ SET_BIT(0xE3); /* For U+3000 */
+#endif
+#ifdef COMPILE_PCRE16
+ SET_BIT(0xA0);
+ SET_BIT(0xFF); /* For characters > 255 */
+#endif
+ }
+ else
+#endif /* SUPPORT_UTF */
+ SET_BIT(0xA0);
+ break;
+
+ case OP_ANYNL:
+ case OP_VSPACE:
+ SET_BIT(0x0A);
+ SET_BIT(0x0B);
+ SET_BIT(0x0C);
+ SET_BIT(0x0D);
+#ifdef COMPILE_PCRE8
+ if (utf)
+ {
+#ifdef COMPILE_PCRE8
+ SET_BIT(0xC2); /* For U+0085 */
+ SET_BIT(0xE2); /* For U+2028, U+2029 */
+#endif
+#ifdef COMPILE_PCRE16
+ SET_BIT(0x85);
+ SET_BIT(0xFF); /* For characters > 255 */
+#endif
+ }
+ else
+#endif /* SUPPORT_UTF */
+ SET_BIT(0x85);
+ break;
+
+ case OP_NOT_DIGIT:
+ set_nottype_bits(start_bits, cbit_digit, table_limit, cd);
+ break;
+
+ case OP_DIGIT:
+ set_type_bits(start_bits, cbit_digit, table_limit, cd);
+ break;
+
+ /* The cbit_space table has vertical tab as whitespace; we have to
+ ensure it gets set as not whitespace. */
+
+ case OP_NOT_WHITESPACE:
+ set_nottype_bits(start_bits, cbit_space, table_limit, cd);
+ start_bits[1] |= 0x08;
+ break;
+
+ /* The cbit_space table has vertical tab as whitespace; we have to
+ avoid setting it. */
+
+ case OP_WHITESPACE:
+ c = start_bits[1]; /* Save in case it was already set */
+ set_type_bits(start_bits, cbit_space, table_limit, cd);
+ start_bits[1] = (start_bits[1] & ~0x08) | c;
+ break;
+
+ case OP_NOT_WORDCHAR:
+ set_nottype_bits(start_bits, cbit_word, table_limit, cd);
+ break;
+
+ case OP_WORDCHAR:
+ set_type_bits(start_bits, cbit_word, table_limit, cd);
+ break;
+ }
+
+ tcode += 2;
+ break;
+
+ /* Character class where all the information is in a bit map: set the
+ bits and either carry on or not, according to the repeat count. If it was
+ a negative class, and we are operating with UTF-8 characters, any byte
+ with a value >= 0xc4 is a potentially valid starter because it starts a
+ character with a value > 255. */
+
+ case OP_NCLASS:
+#if defined SUPPORT_UTF && defined COMPILE_PCRE8
+ if (utf)
+ {
+ start_bits[24] |= 0xf0; /* Bits for 0xc4 - 0xc8 */
+ memset(start_bits+25, 0xff, 7); /* Bits for 0xc9 - 0xff */
+ }
+#endif
+#ifdef COMPILE_PCRE16
+ SET_BIT(0xFF); /* For characters > 255 */
+#endif
+ /* Fall through */
+
+ case OP_CLASS:
+ {
+ pcre_uint8 *map;
+ tcode++;
+ map = (pcre_uint8 *)tcode;
+
+ /* In UTF-8 mode, the bits in a bit map correspond to character
+ values, not to byte values. However, the bit map we are constructing is
+ for byte values. So we have to do a conversion for characters whose
+ value is > 127. In fact, there are only two possible starting bytes for
+ characters in the range 128 - 255. */
+
+#if defined SUPPORT_UTF && defined COMPILE_PCRE8
+ if (utf)
+ {
+ for (c = 0; c < 16; c++) start_bits[c] |= map[c];
+ for (c = 128; c < 256; c++)
+ {
+ if ((map[c/8] && (1 << (c&7))) != 0)
+ {
+ int d = (c >> 6) | 0xc0; /* Set bit for this starter */
+ start_bits[d/8] |= (1 << (d&7)); /* and then skip on to the */
+ c = (c & 0xc0) + 0x40 - 1; /* next relevant character. */
+ }
+ }
+ }
+ else
+#endif
+ {
+ /* In non-UTF-8 mode, the two bit maps are completely compatible. */
+ for (c = 0; c < 32; c++) start_bits[c] |= map[c];
+ }
+
+ /* Advance past the bit map, and act on what follows. For a zero
+ minimum repeat, continue; otherwise stop processing. */
+
+ tcode += 32 / sizeof(pcre_uchar);
+ switch (*tcode)
+ {
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ tcode++;
+ break;
+
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ if (GET2(tcode, 1) == 0) tcode += 1 + 2 * IMM2_SIZE;
+ else try_next = FALSE;
+ break;
+
+ default:
+ try_next = FALSE;
+ break;
+ }
+ }
+ break; /* End of bitmap class handling */
+
+ } /* End of switch */
+ } /* End of try_next loop */
+
+ code += GET(code, 1); /* Advance to next branch */
+ }
+while (*code == OP_ALT);
+return yield;
+}
+
+
+
+
+
+/*************************************************
+* Study a compiled expression *
+*************************************************/
+
+/* This function is handed a compiled expression that it must study to produce
+information that will speed up the matching. It returns a pcre[16]_extra block
+which then gets handed back to pcre_exec().
+
+Arguments:
+ re points to the compiled expression
+ options contains option bits
+ errorptr points to where to place error messages;
+ set NULL unless error
+
+Returns: pointer to a pcre[16]_extra block, with study_data filled in and
+ the appropriate flags set;
+ NULL on error or if no optimization possible
+*/
+
+#ifdef COMPILE_PCRE8
+PCRE_EXP_DEFN pcre_extra * PCRE_CALL_CONVENTION
+pcre_study(const pcre *external_re, int options, const char **errorptr)
+#else
+PCRE_EXP_DEFN pcre16_extra * PCRE_CALL_CONVENTION
+pcre16_study(const pcre16 *external_re, int options, const char **errorptr)
+#endif
+{
+int min;
+BOOL bits_set = FALSE;
+pcre_uint8 start_bits[32];
+PUBL(extra) *extra = NULL;
+pcre_study_data *study;
+const pcre_uint8 *tables;
+pcre_uchar *code;
+compile_data compile_block;
+const REAL_PCRE *re = (const REAL_PCRE *)external_re;
+
+*errorptr = NULL;
+
+if (re == NULL || re->magic_number != MAGIC_NUMBER)
+ {
+ *errorptr = "argument is not a compiled regular expression";
+ return NULL;
+ }
+
+if ((re->flags & PCRE_MODE) == 0)
+ {
+#ifdef COMPILE_PCRE8
+ *errorptr = "argument is compiled in 16 bit mode";
+#else
+ *errorptr = "argument is compiled in 8 bit mode";
+#endif
+ return NULL;
+ }
+
+if ((options & ~PUBLIC_STUDY_OPTIONS) != 0)
+ {
+ *errorptr = "unknown or incorrect option bit(s) set";
+ return NULL;
+ }
+
+code = (pcre_uchar *)re + re->name_table_offset +
+ (re->name_count * re->name_entry_size);
+
+/* For an anchored pattern, or an unanchored pattern that has a first char, or
+a multiline pattern that matches only at "line starts", there is no point in
+seeking a list of starting bytes. */
+
+if ((re->options & PCRE_ANCHORED) == 0 &&
+ (re->flags & (PCRE_FIRSTSET|PCRE_STARTLINE)) == 0)
+ {
+ int rc;
+
+ /* Set the character tables in the block that is passed around */
+
+ tables = re->tables;
+
+#ifdef COMPILE_PCRE8
+ if (tables == NULL)
+ (void)pcre_fullinfo(external_re, NULL, PCRE_INFO_DEFAULT_TABLES,
+ (void *)(&tables));
+#else
+ if (tables == NULL)
+ (void)pcre16_fullinfo(external_re, NULL, PCRE_INFO_DEFAULT_TABLES,
+ (void *)(&tables));
+#endif
+
+ compile_block.lcc = tables + lcc_offset;
+ compile_block.fcc = tables + fcc_offset;
+ compile_block.cbits = tables + cbits_offset;
+ compile_block.ctypes = tables + ctypes_offset;
+
+ /* See if we can find a fixed set of initial characters for the pattern. */
+
+ memset(start_bits, 0, 32 * sizeof(pcre_uint8));
+ rc = set_start_bits(code, start_bits, (re->options & PCRE_UTF8) != 0,
+ &compile_block);
+ bits_set = rc == SSB_DONE;
+ if (rc == SSB_UNKNOWN)
+ {
+ *errorptr = "internal error: opcode not recognized";
+ return NULL;
+ }
+ }
+
+/* Find the minimum length of subject string. */
+
+switch(min = find_minlength(code, code, re->options, 0))
+ {
+ case -2: *errorptr = "internal error: missing capturing bracket"; return NULL;
+ case -3: *errorptr = "internal error: opcode not recognized"; return NULL;
+ default: break;
+ }
+
+/* If a set of starting bytes has been identified, or if the minimum length is
+greater than zero, or if JIT optimization has been requested, get a
+pcre[16]_extra block and a pcre_study_data block. The study data is put in the
+latter, which is pointed to by the former, which may also get additional data
+set later by the calling program. At the moment, the size of pcre_study_data
+is fixed. We nevertheless save it in a field for returning via the
+pcre_fullinfo() function so that if it becomes variable in the future,
+we don't have to change that code. */
+
+if (bits_set || min > 0
+#ifdef SUPPORT_JIT
+ || (options & PCRE_STUDY_JIT_COMPILE) != 0
+#endif
+ )
+ {
+ extra = (PUBL(extra) *)(PUBL(malloc))
+ (sizeof(PUBL(extra)) + sizeof(pcre_study_data));
+ if (extra == NULL)
+ {
+ *errorptr = "failed to get memory";
+ return NULL;
+ }
+
+ study = (pcre_study_data *)((char *)extra + sizeof(PUBL(extra)));
+ extra->flags = PCRE_EXTRA_STUDY_DATA;
+ extra->study_data = study;
+
+ study->size = sizeof(pcre_study_data);
+ study->flags = 0;
+
+ /* Set the start bits always, to avoid unset memory errors if the
+ study data is written to a file, but set the flag only if any of the bits
+ are set, to save time looking when none are. */
+
+ if (bits_set)
+ {
+ study->flags |= PCRE_STUDY_MAPPED;
+ memcpy(study->start_bits, start_bits, sizeof(start_bits));
+ }
+ else memset(study->start_bits, 0, 32 * sizeof(pcre_uint8));
+
+#ifdef PCRE_DEBUG
+ if (bits_set)
+ {
+ pcre_uint8 *ptr = start_bits;
+ int i;
+
+ printf("Start bits:\n");
+ for (i = 0; i < 32; i++)
+ printf("%3d: %02x%s", i * 8, *ptr++, ((i + 1) & 0x7) != 0? " " : "\n");
+ }
+#endif
+
+ /* Always set the minlength value in the block, because the JIT compiler
+ makes use of it. However, don't set the bit unless the length is greater than
+ zero - the interpretive pcre_exec() and pcre_dfa_exec() needn't waste time
+ checking the zero case. */
+
+ if (min > 0)
+ {
+ study->flags |= PCRE_STUDY_MINLEN;
+ study->minlength = min;
+ }
+ else study->minlength = 0;
+
+ /* If JIT support was compiled and requested, attempt the JIT compilation.
+ If no starting bytes were found, and the minimum length is zero, and JIT
+ compilation fails, abandon the extra block and return NULL. */
+
+#ifdef SUPPORT_JIT
+ extra->executable_jit = NULL;
+ if ((options & PCRE_STUDY_JIT_COMPILE) != 0) PRIV(jit_compile)(re, extra);
+ if (study->flags == 0 && (extra->flags & PCRE_EXTRA_EXECUTABLE_JIT) == 0)
+ {
+#ifdef COMPILE_PCRE8
+ pcre_free_study(extra);
+#endif
+#ifdef COMPILE_PCRE16
+ pcre16_free_study(extra);
+#endif
+ extra = NULL;
+ }
+#endif
+ }
+
+return extra;
+}
+
+
+/*************************************************
+* Free the study data *
+*************************************************/
+
+/* This function frees the memory that was obtained by pcre_study().
+
+Argument: a pointer to the pcre[16]_extra block
+Returns: nothing
+*/
+
+#ifdef COMPILE_PCRE8
+PCRE_EXP_DEFN void
+pcre_free_study(pcre_extra *extra)
+#else
+PCRE_EXP_DEFN void
+pcre16_free_study(pcre16_extra *extra)
+#endif
+{
+if (extra == NULL)
+ return;
+#ifdef SUPPORT_JIT
+if ((extra->flags & PCRE_EXTRA_EXECUTABLE_JIT) != 0 &&
+ extra->executable_jit != NULL)
+ PRIV(jit_free)(extra->executable_jit);
+#endif
+PUBL(free)(extra);
+}
+
+/* End of pcre_study.c */